summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Jon McCann <mccann@src.gnome.org>2007-05-10 20:12:49 +0000
committerWilliam Jon McCann <mccann@src.gnome.org>2007-05-10 20:12:49 +0000
commitb961c279e609ae1080c8a21e5e51f901f17cf223 (patch)
treecf06abdc5ea0d7fef67b713bd874aada9e25a2e3
parent088ff8dba8a807cb4ed0e7a5f5bfc4b784cec2a7 (diff)
downloadgdm-b961c279e609ae1080c8a21e5e51f901f17cf223.tar.gz
Add skeleton for gobject redesign. Doesn't really work but should compile.
svn path=/branches/mccann-gobject/; revision=4911
-rw-r--r--Makefile.am3
-rw-r--r--common/Makefile.am2
-rw-r--r--common/gdm-address.c354
-rw-r--r--common/gdm-address.h69
-rw-r--r--common/gdm-common.c749
-rw-r--r--common/gdm-common.h107
-rw-r--r--configure.ac30
-rw-r--r--daemon/Makefile.am132
-rw-r--r--daemon/auth.c244
-rw-r--r--daemon/auth.h30
-rw-r--r--daemon/choose.c122
-rw-r--r--daemon/choose.h18
-rw-r--r--daemon/cookie.c2
-rw-r--r--daemon/cookie.h2
-rw-r--r--daemon/display.c13
-rw-r--r--daemon/display.h27
-rw-r--r--daemon/filecheck.c34
-rw-r--r--daemon/gdm-daemon-config-entries.h2
-rw-r--r--daemon/gdm-daemon-config.c262
-rw-r--r--daemon/gdm-daemon-config.h1
-rw-r--r--daemon/gdm-display-store.c219
-rw-r--r--daemon/gdm-display-store.h89
-rw-r--r--daemon/gdm-display.c546
-rw-r--r--daemon/gdm-display.h98
-rw-r--r--daemon/gdm-display.xml17
-rw-r--r--daemon/gdm-greeter.c1147
-rw-r--r--daemon/gdm-greeter.h57
-rw-r--r--daemon/gdm-manager.c433
-rw-r--r--daemon/gdm-manager.h71
-rw-r--r--daemon/gdm-manager.xml14
-rw-r--r--daemon/gdm-master-config.c941
-rw-r--r--daemon/gdm-master-config.h93
-rw-r--r--daemon/gdm-net.c16
-rw-r--r--daemon/gdm-server.c708
-rw-r--r--daemon/gdm-server.h57
-rw-r--r--daemon/gdm-slave-proxy.c441
-rw-r--r--daemon/gdm-slave-proxy.h57
-rw-r--r--daemon/gdm-slave.c984
-rw-r--r--daemon/gdm-slave.h56
-rw-r--r--daemon/gdm-slave.xml5
-rw-r--r--daemon/gdm-static-display.c175
-rw-r--r--daemon/gdm-static-display.h61
-rw-r--r--daemon/gdm-static-display.xml5
-rw-r--r--daemon/gdm-xdmcp-display.c329
-rw-r--r--daemon/gdm-xdmcp-display.h77
-rw-r--r--daemon/gdm-xdmcp-display.xml5
-rw-r--r--daemon/gdm-xdmcp-manager.c1250
-rw-r--r--daemon/gdm-xdmcp-manager.h4
-rw-r--r--daemon/gdm.c4334
-rw-r--r--daemon/gdm.h31
-rw-r--r--daemon/main.c596
-rw-r--r--daemon/misc.c754
-rw-r--r--daemon/misc.h91
-rw-r--r--daemon/server.h17
-rw-r--r--daemon/slave-main.c140
-rw-r--r--daemon/slave.c57
-rw-r--r--daemon/xdmcp.c141
-rw-r--r--daemon/xdmcp.h31
-rw-r--r--data/Makefile.am12
-rw-r--r--data/gdm.conf31
-rw-r--r--gui/gdmconfig.c2
-rw-r--r--gui/gdmconfig.h27
62 files changed, 9695 insertions, 6727 deletions
diff --git a/Makefile.am b/Makefile.am
index 03d0dadb..fe16cf47 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
NULL =
SUBDIRS = \
- po \
+ data \
config \
pixmaps \
common \
@@ -9,6 +9,7 @@ SUBDIRS = \
gui \
utils \
docs \
+ po \
$(NULL)
# add these when help gets added back
diff --git a/common/Makefile.am b/common/Makefile.am
index ed049d63..cc6b0e11 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -28,6 +28,8 @@ noinst_LIBRARIES = \
$(null)
libgdmcommon_a_SOURCES = \
+ gdm-address.h \
+ gdm-address.c \
gdm-common.h \
gdm-common.c \
gdm-common-config.h \
diff --git a/common/gdm-address.c b/common/gdm-address.c
new file mode 100644
index 00000000..b5cf08da
--- /dev/null
+++ b/common/gdm-address.c
@@ -0,0 +1,354 @@
+/* -*- 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>
+
+#ifndef G_OS_WIN32
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <glib-object.h>
+
+#include "gdm-address.h"
+
+struct _GdmAddress
+{
+ struct sockaddr_storage *ss;
+};
+
+/* Register GdmAddress in the glib type system */
+GType
+gdm_address_get_type (void)
+{
+ static GType addr_type = 0;
+
+ if (addr_type == 0) {
+ addr_type = g_boxed_type_register_static ("GdmAddress",
+ (GBoxedCopyFunc) gdm_address_copy,
+ (GBoxedFreeFunc) gdm_address_free);
+ }
+
+ return addr_type;
+}
+
+/**
+ * gdm_address_get_family_type:
+ * @address: A pointer to a #GdmAddress
+ *
+ * Use this function to retrive the address family of @address.
+ *
+ * Return value: The address family of @address.
+ **/
+int
+gdm_address_get_family_type (GdmAddress *address)
+{
+ g_return_val_if_fail (address != NULL, -1);
+
+ return address->ss->ss_family;
+}
+
+
+/**
+ * gdm_address_new_from_sockaddr:
+ * @sa: A pointer to a sockaddr_storage.
+ *
+ * Creates a new #GdmAddress from @ss.
+ *
+ * Return value: The new #GdmAddress
+ * or %NULL if @sa was invalid or the address family isn't supported.
+ **/
+GdmAddress *
+gdm_address_new_from_sockaddr_storage (struct sockaddr_storage *ss)
+{
+ GdmAddress *addr;
+
+ g_return_val_if_fail (ss != NULL, NULL);
+
+ addr = g_new0 (GdmAddress, 1);
+ addr->ss = g_memdup (ss, sizeof (struct sockaddr_storage));
+
+ return addr;
+}
+
+/**
+ * gdm_address_get_sockaddr_storage:
+ * @address: A #GdmAddress
+ *
+ * This function tanslates @address into a equivalent
+ * sockaddr_storage
+ *
+ * Return value: A newly allocated sockaddr_storage structure the caller must free
+ * or %NULL if @address did not point to a valid #GdmAddress.
+ **/
+struct sockaddr_storage *
+gdm_address_get_sockaddr_storage (GdmAddress *address)
+{
+ struct sockaddr_storage *ss;
+
+ g_return_val_if_fail (address != NULL, NULL);
+
+ ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
+
+ return ss;
+}
+
+struct sockaddr_storage *
+gdm_address_peek_sockaddr_storage (GdmAddress *address)
+{
+ g_return_val_if_fail (address != NULL, NULL);
+
+ return address->ss;
+}
+
+static gboolean
+v4_v4_equal (const struct sockaddr_in *a,
+ const struct sockaddr_in *b)
+{
+ return a->sin_addr.s_addr == b->sin_addr.s_addr;
+}
+
+#ifdef ENABLE_IPV6
+static gboolean
+v6_v6_equal (struct sockaddr_in6 *a,
+ struct sockaddr_in6 *b)
+{
+ return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
+}
+#endif
+
+#define SA(__s) ((struct sockaddr *) __s)
+#define SIN(__s) ((struct sockaddr_in *) __s)
+#define SIN6(__s) ((struct sockaddr_in6 *) __s)
+
+gboolean
+gdm_address_equal (GdmAddress *a,
+ GdmAddress *b)
+{
+ guint8 fam_a;
+ guint8 fam_b;
+
+ g_return_val_if_fail (a != NULL || a->ss != NULL, FALSE);
+ g_return_val_if_fail (b != NULL || b->ss != NULL, FALSE);
+
+ fam_a = a->ss->ss_family;
+ fam_b = b->ss->ss_family;
+
+ if (fam_a == AF_INET && fam_b == AF_INET) {
+ return v4_v4_equal (SIN (a->ss), SIN (b->ss));
+ }
+#ifdef ENABLE_IPV6
+ else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
+ return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
+ }
+#endif
+ return FALSE;
+}
+
+char *
+gdm_address_get_hostname (GdmAddress *address)
+{
+ char host [NI_MAXHOST];
+
+ g_return_val_if_fail (address != NULL || address->ss != NULL, NULL);
+
+ host [0] = '\0';
+ getnameinfo ((const struct sockaddr *)address->ss,
+ sizeof (struct sockaddr_storage),
+ host, sizeof (host),
+ NULL, 0,
+ 0);
+
+ return g_strdup (host);
+}
+
+void
+gdm_address_get_numeric_info (GdmAddress *address,
+ char **hostp,
+ char **servp)
+{
+ char host [NI_MAXHOST];
+ char serv [NI_MAXSERV];
+
+ g_return_if_fail (address != NULL || address->ss != NULL);
+
+ host [0] = '\0';
+ serv [0] = '\0';
+ getnameinfo ((const struct sockaddr *)address->ss,
+ sizeof (struct sockaddr_storage),
+ host, sizeof (host),
+ serv, sizeof (serv),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (servp != NULL) {
+ *servp = g_strdup (serv);
+ }
+ if (hostp != NULL) {
+ *hostp = g_strdup (host);
+ }
+}
+
+gboolean
+gdm_address_is_loopback (GdmAddress *address)
+{
+ g_return_val_if_fail (address != NULL || address->ss != NULL, FALSE);
+
+ switch (address->ss->ss_family){
+#ifdef AF_INET6
+ case AF_INET6:
+ return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)address->ss)->sin6_addr);
+ break;
+#endif
+ case AF_INET:
+ return (INADDR_LOOPBACK == (((struct sockaddr_in *)address->ss)->sin_addr.s_addr));
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+const GList *
+gdm_address_peek_local_list (void)
+{
+ static GList *the_list = NULL;
+ static time_t last_time = 0;
+ char hostbuf[BUFSIZ];
+ struct addrinfo hints;
+ struct addrinfo *result;
+ struct addrinfo *res;
+
+ /* Don't check more then every 5 seconds */
+ if (last_time + 5 > time (NULL)) {
+ return the_list;
+ }
+
+ g_list_foreach (the_list, (GFunc)gdm_address_free, NULL);
+ g_list_free (the_list);
+ the_list = NULL;
+
+ last_time = time (NULL);
+
+ hostbuf[BUFSIZ-1] = '\0';
+ if (gethostname (hostbuf, BUFSIZ-1) != 0) {
+ g_debug ("%s: Could not get server hostname, using localhost", "gdm_peek_local_address_list");
+ snprintf (hostbuf, BUFSIZ-1, "localhost");
+ }
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = AF_INET;
+#ifdef ENABLE_IPV6
+ hints.ai_family |= AF_INET6;
+#endif
+
+ if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
+ g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
+
+ return NULL;
+ }
+
+ for (res = result; res != NULL; res = res->ai_next) {
+ GdmAddress *address;
+
+ address = gdm_address_new_from_sockaddr_storage ((struct sockaddr_storage *)res->ai_addr);
+ the_list = g_list_append (the_list, address);
+ }
+
+ if (result != NULL) {
+ freeaddrinfo (result);
+ result = NULL;
+ }
+
+ return the_list;
+}
+
+gboolean
+gdm_address_is_local (GdmAddress *address)
+{
+ const GList *list;
+
+ if (gdm_address_is_loopback (address)) {
+ return TRUE;
+ }
+
+ list = gdm_address_peek_local_list ();
+
+ while (list != NULL) {
+ GdmAddress *addr = list->data;
+
+ if (gdm_address_equal (address, addr)) {
+ return TRUE;
+ }
+
+ list = list->next;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gdm_address_copy:
+ * @address: A #GdmAddress.
+ *
+ * Duplicates @address.
+ *
+ * Return value: Duplicated @address or %NULL if @address was not valid.
+ **/
+GdmAddress *
+gdm_address_copy (GdmAddress *address)
+{
+ GdmAddress *addr;
+
+ g_return_val_if_fail (address != NULL, NULL);
+
+ addr = g_new0 (GdmAddress, 1);
+ addr->ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
+
+ return addr;
+}
+
+/**
+ * gdm_address_free:
+ * @address: A #GdmAddress.
+ *
+ * Frees the memory allocated for @address.
+ **/
+void
+gdm_address_free (GdmAddress *address)
+{
+ g_return_if_fail (address != NULL);
+
+ g_free (address->ss);
+ g_free (address);
+}
+
+
diff --git a/common/gdm-address.h b/common/gdm-address.h
new file mode 100644
index 00000000..14e1ef13
--- /dev/null
+++ b/common/gdm-address.h
@@ -0,0 +1,69 @@
+/* -*- 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_ADDRESS_H
+#define __GDM_ADDRESS_H
+
+#include <glib-object.h>
+#ifndef G_OS_WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#else
+#include <winsock2.h>
+#undef interface
+#endif
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_ADDRESS (gdm_address_get_type ())
+
+typedef struct _GdmAddress GdmAddress;
+
+GType gdm_address_get_type (void);
+
+GdmAddress * gdm_address_new_from_sockaddr_storage (struct sockaddr_storage *ss);
+
+int gdm_address_get_family_type (GdmAddress *address);
+struct sockaddr_storage *gdm_address_get_sockaddr_storage (GdmAddress *address);
+struct sockaddr_storage *gdm_address_peek_sockaddr_storage (GdmAddress *address);
+
+char * gdm_address_get_hostname (GdmAddress *address);
+void gdm_address_get_numeric_info (GdmAddress *address,
+ char **numeric_hostname,
+ char **service);
+gboolean gdm_address_is_local (GdmAddress *address);
+gboolean gdm_address_is_loopback (GdmAddress *address);
+
+gboolean gdm_address_equal (GdmAddress *a,
+ GdmAddress *b);
+
+GdmAddress * gdm_address_copy (GdmAddress *address);
+void gdm_address_free (GdmAddress *address);
+
+
+
+const GList * gdm_address_peek_local_list (void);
+
+
+G_END_DECLS
+
+#endif /* __GDM_ADDRESS_H */
diff --git a/common/gdm-common.c b/common/gdm-common.c
index dbb3ff31..73e78b9f 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -25,98 +25,726 @@
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <setjmp.h>
+#include <dirent.h>
#ifdef HAVE_CRT_EXTERNS_H
#include <crt_externs.h>
#endif
+#include <glib.h>
+#include <glib/gi18n.h>
+
#include "gdm-common.h"
-static gboolean
-v4_v4_equal (const struct sockaddr_in *a,
- const struct sockaddr_in *b)
+int
+gdm_fdgetc (int fd)
{
- return a->sin_addr.s_addr == b->sin_addr.s_addr;
+ char buf[1];
+ int bytes;
+
+ VE_IGNORE_EINTR (bytes = read (fd, buf, 1));
+ if (bytes != 1)
+ return EOF;
+ else
+ return (int)buf[0];
}
-#ifdef ENABLE_IPV6
-static gboolean
-v6_v6_equal (struct sockaddr_in6 *a,
- struct sockaddr_in6 *b)
+char *
+gdm_fdgets (int fd)
{
- return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
+ int c;
+ int bytes = 0;
+ GString *gs = g_string_new (NULL);
+ for (;;) {
+ c = gdm_fdgetc (fd);
+ if (c == '\n')
+ return g_string_free (gs, FALSE);
+ /* on EOF */
+ if (c < 0) {
+ if (bytes == 0) {
+ g_string_free (gs, TRUE);
+ return NULL;
+ } else {
+ return g_string_free (gs, FALSE);
+ }
+ } else {
+ bytes++;
+ g_string_append_c (gs, c);
+ }
+ }
}
-#endif
-#define SA(__s) ((struct sockaddr *) __s)
-#define SIN(__s) ((struct sockaddr_in *) __s)
-#define SIN6(__s) ((struct sockaddr_in6 *) __s)
+void
+gdm_fdprintf (int fd, const gchar *format, ...)
+{
+ va_list args;
+ gchar *s;
+ int written, len;
-gboolean
-gdm_address_equal (struct sockaddr_storage *sa,
- struct sockaddr_storage *sb)
+ va_start (args, format);
+ s = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ len = strlen (s);
+
+ if (len == 0) {
+ g_free (s);
+ return;
+ }
+
+ written = 0;
+ while (written < len) {
+ int w;
+ VE_IGNORE_EINTR (w = write (fd, &s[written], len - written));
+ if (w < 0)
+ /* evil! */
+ break;
+ written += w;
+ }
+
+ g_free (s);
+}
+
+void
+gdm_close_all_descriptors (int from, int except, int except2)
{
- guint8 fam_a;
- guint8 fam_b;
+ DIR *dir;
+ struct dirent *ent;
+ GSList *openfds = NULL;
+
+ /*
+ * Evil, but less evil then going to _SC_OPEN_MAX
+ * which can be very VERY large
+ */
+ dir = opendir ("/proc/self/fd/"); /* This is the Linux dir */
+ if (dir == NULL)
+ dir = opendir ("/dev/fd/"); /* This is the FreeBSD dir */
+ if G_LIKELY (dir != NULL) {
+ GSList *li;
+ while ((ent = readdir (dir)) != NULL) {
+ int fd;
+ if (ent->d_name[0] == '.')
+ continue;
+ fd = atoi (ent->d_name);
+ if (fd >= from && fd != except && fd != except2)
+ openfds = g_slist_prepend (openfds, GINT_TO_POINTER (fd));
+ }
+ closedir (dir);
+ for (li = openfds; li != NULL; li = li->next) {
+ int fd = GPOINTER_TO_INT (li->data);
+ VE_IGNORE_EINTR (close (fd));
+ }
+ g_slist_free (openfds);
+ } else {
+ int i;
+ int max = sysconf (_SC_OPEN_MAX);
+ /*
+ * Don't go higher then this. This is
+ * a safety measure to not hang on crazy
+ * systems
+ */
+ if G_UNLIKELY (max > 4096) {
+ /* FIXME: warn about this perhaps */
+ /*
+ * Try an open, in case we're really
+ * leaking fds somewhere badly, this
+ * should be very high
+ */
+ i = gdm_open_dev_null (O_RDONLY);
+ max = MAX (i+1, 4096);
+ }
+ for (i = from; i < max; i++) {
+ if G_LIKELY (i != except && i != except2)
+ VE_IGNORE_EINTR (close (i));
+ }
+ }
+}
+
+void
+gdm_signal_ignore (int signal)
+{
+ struct sigaction ign_signal;
+
+ ign_signal.sa_handler = SIG_IGN;
+ ign_signal.sa_flags = SA_RESTART;
+ sigemptyset (&ign_signal.sa_mask);
+
+ if G_UNLIKELY (sigaction (signal, &ign_signal, NULL) < 0)
+ g_warning (_("%s: Error setting signal %d to %s"),
+ "gdm_signal_ignore", signal, "SIG_IGN");
+}
+
+void
+gdm_signal_default (int signal)
+{
+ struct sigaction def_signal;
- g_return_val_if_fail (sa != NULL, FALSE);
- g_return_val_if_fail (sb != NULL, FALSE);
+ def_signal.sa_handler = SIG_DFL;
+ def_signal.sa_flags = SA_RESTART;
+ sigemptyset (&def_signal.sa_mask);
- fam_a = sa->ss_family;
- fam_b = sb->ss_family;
+ if G_UNLIKELY (sigaction (signal, &def_signal, NULL) < 0)
+ g_warning (_("%s: Error setting signal %d to %s"),
+ "gdm_signal_ignore", signal, "SIG_DFL");
+}
- if (fam_a == AF_INET && fam_b == AF_INET) {
- return v4_v4_equal (SIN (sa), SIN (sb));
+int
+gdm_open_dev_null (mode_t mode)
+{
+ int ret;
+ VE_IGNORE_EINTR (ret = open ("/dev/null", mode));
+ if G_UNLIKELY (ret < 0) {
+ /*
+ * Never output anything, we're likely in some
+ * strange state right now
+ */
+ gdm_signal_ignore (SIGPIPE);
+ VE_IGNORE_EINTR (close (2));
+ g_error ("Cannot open /dev/null, system on crack!");
}
-#ifdef ENABLE_IPV6
- else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
- return v6_v6_equal (SIN6 (sa), SIN6 (sb));
+
+ return ret;
+}
+
+char *
+gdm_make_filename (const char *dir,
+ const char *name,
+ const char *extension)
+{
+ char *base = g_strconcat (name, extension, NULL);
+ char *full = g_build_filename (dir, base, NULL);
+ g_free (base);
+ return full;
+}
+
+
+static int sigchld_blocked = 0;
+static sigset_t sigchldblock_mask, sigchldblock_oldmask;
+
+static int sigterm_blocked = 0;
+static sigset_t sigtermblock_mask, sigtermblock_oldmask;
+
+static int sigusr2_blocked = 0;
+static sigset_t sigusr2block_mask, sigusr2block_oldmask;
+
+void
+gdm_sigchld_block_push (void)
+{
+ sigchld_blocked++;
+
+ if (sigchld_blocked == 1) {
+ /* Set signal mask */
+ sigemptyset (&sigchldblock_mask);
+ sigaddset (&sigchldblock_mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &sigchldblock_mask, &sigchldblock_oldmask);
}
-#endif
- return FALSE;
}
-gboolean
-gdm_address_is_loopback (struct sockaddr_storage *sa)
+void
+gdm_sigchld_block_pop (void)
+{
+ sigchld_blocked --;
+
+ if (sigchld_blocked == 0) {
+ /* Reset signal mask back */
+ sigprocmask (SIG_SETMASK, &sigchldblock_oldmask, NULL);
+ }
+}
+
+void
+gdm_sigterm_block_push (void)
+{
+ sigterm_blocked++;
+
+ if (sigterm_blocked == 1) {
+ /* Set signal mask */
+ sigemptyset (&sigtermblock_mask);
+ sigaddset (&sigtermblock_mask, SIGTERM);
+ sigaddset (&sigtermblock_mask, SIGINT);
+ sigaddset (&sigtermblock_mask, SIGHUP);
+ sigprocmask (SIG_BLOCK, &sigtermblock_mask, &sigtermblock_oldmask);
+ }
+}
+
+void
+gdm_sigterm_block_pop (void)
+{
+ sigterm_blocked --;
+
+ if (sigterm_blocked == 0) {
+ /* Reset signal mask back */
+ sigprocmask (SIG_SETMASK, &sigtermblock_oldmask, NULL);
+ }
+}
+
+void
+gdm_sigusr2_block_push (void)
+{
+ sigset_t oldmask;
+
+ if (sigusr2_blocked == 0) {
+ /* Set signal mask */
+ sigemptyset (&sigusr2block_mask);
+ sigaddset (&sigusr2block_mask, SIGUSR2);
+ sigprocmask (SIG_BLOCK, &sigusr2block_mask, &oldmask);
+ }
+
+ sigusr2_blocked++;
+
+ sigusr2block_oldmask = oldmask;
+}
+
+void
+gdm_sigusr2_block_pop (void)
+{
+ sigset_t oldmask;
+
+ oldmask = sigusr2block_oldmask;
+
+ sigusr2_blocked--;
+
+ if (sigusr2_blocked == 0) {
+ /* Reset signal mask back */
+ sigprocmask (SIG_SETMASK, &sigusr2block_oldmask, NULL);
+ }
+}
+
+static GdmHostent *
+fillout_addrinfo (struct addrinfo *res,
+ struct sockaddr *ia,
+ const char *name)
{
- switch(sa->ss_family){
-#ifdef AF_INET6
- case AF_INET6:
- return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)sa)->sin6_addr);
- break;
+ GdmHostent *he;
+ gint i;
+ gint addr_count = 0;
+ struct addrinfo *tempaddrinfo;
+
+ he = g_new0 (GdmHostent, 1);
+
+ he->addrs = NULL;
+ he->addr_count = 0;
+
+ if (res != NULL && res->ai_canonname != NULL) {
+ he->hostname = g_strdup (res->ai_canonname);
+ he->not_found = FALSE;
+ } else {
+ he->not_found = TRUE;
+ if (name != NULL)
+ he->hostname = g_strdup (name);
+ else {
+ static char buffer6[INET6_ADDRSTRLEN];
+ static char buffer[INET_ADDRSTRLEN];
+ const char *new = NULL;
+
+ if (ia->sa_family == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)ia)->sin6_addr)) {
+ new = inet_ntop (AF_INET, &(((struct sockaddr_in6 *)ia)->sin6_addr.s6_addr[12]), buffer, sizeof (buffer));
+ } else {
+ new = inet_ntop (AF_INET6, &((struct sockaddr_in6 *)ia)->sin6_addr, buffer6, sizeof (buffer6));
+ }
+ } else if (ia->sa_family == AF_INET) {
+ new = inet_ntop (AF_INET, &((struct sockaddr_in *)ia)->sin_addr, buffer, sizeof (buffer));
+ }
+
+ if (new != NULL) {
+ he->hostname = g_strdup (new);
+ } else {
+ he->hostname = NULL;
+ }
+ }
+ }
+
+ tempaddrinfo = res;
+
+ while (res != NULL) {
+ addr_count++;
+ res = res->ai_next;
+ }
+
+ he->addrs = g_new0 (struct sockaddr_storage, addr_count);
+ he->addr_count = addr_count;
+ res = tempaddrinfo;
+ for (i = 0; ; i++) {
+ if (res == NULL)
+ break;
+
+ if ((res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) {
+ (he->addrs)[i] = *(struct sockaddr_storage *)(res->ai_addr);
+ }
+
+ res = res->ai_next;
+ }
+
+ /* We don't want the ::ffff: that could arise here */
+ if (he->hostname != NULL &&
+ strncmp (he->hostname, "::ffff:", 7) == 0) {
+ strcpy (he->hostname, he->hostname + 7);
+ }
+
+ return he;
+}
+
+/* stolen from xdm sources */
+#if defined(X_NOT_POSIX) || defined(__EMX__) || defined(__NetBSD__) && defined(__sparc__)
+#define Setjmp(e) setjmp(e)
+#define Longjmp(e,v) longjmp(e,v)
+#define Jmp_buf jmp_buf
+#else
+#define Setjmp(e) sigsetjmp(e,1)
+#define Longjmp(e,v) siglongjmp(e,v)
+#define Jmp_buf sigjmp_buf
#endif
- case AF_INET:
- return (INADDR_LOOPBACK == (((struct sockaddr_in *)sa)->sin_addr.s_addr));
- break;
- default:
- break;
+
+static gboolean do_jumpback = FALSE;
+static Jmp_buf signal_jumpback;
+static struct sigaction oldterm, oldint, oldhup;
+
+static void
+jumpback_sighandler (int signal)
+{
+ /*
+ * This avoids a race see Note below.
+ * We want to jump back only on the first
+ * signal invocation, even if the signal
+ * handler didn't return.
+ */
+ gboolean old_do_jumpback = do_jumpback;
+ do_jumpback = FALSE;
+
+ if (signal == SIGINT)
+ oldint.sa_handler (signal);
+ else if (signal == SIGTERM)
+ oldint.sa_handler (signal);
+ else if (signal == SIGHUP)
+ oldint.sa_handler (signal);
+ /* No others should be set up */
+
+ /* Note that we may not get here since
+ the SIGTERM handler in slave.c
+ might have in fact done the big Longjmp
+ to the slave's death */
+
+ if (old_do_jumpback) {
+ Longjmp (signal_jumpback, 1);
+ }
+}
+
+/*
+ * This sets up interruptes to be proxied and the
+ * gethostbyname/addr to be whacked using longjmp,
+ * in case INT/TERM/HUP was gotten in which case
+ * we no longer care for the result of the
+ * resolution.
+ */
+#define SETUP_INTERRUPTS_FOR_TERM_DECLS \
+ struct sigaction term;
+
+#define SETUP_INTERRUPTS_FOR_TERM_SETUP \
+ do_jumpback = FALSE; \
+ \
+ term.sa_handler = jumpback_sighandler; \
+ term.sa_flags = SA_RESTART; \
+ sigemptyset (&term.sa_mask); \
+ \
+ if G_UNLIKELY (sigaction (SIGTERM, &term, &oldterm) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "TERM", g_strerror (errno)); \
+ \
+ if G_UNLIKELY (sigaction (SIGINT, &term, &oldint) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "INT", g_strerror (errno)); \
+ \
+ if G_UNLIKELY (sigaction (SIGHUP, &term, &oldhup) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "HUP", g_strerror (errno)); \
+
+#define SETUP_INTERRUPTS_FOR_TERM_TEARDOWN \
+ do_jumpback = FALSE; \
+ \
+ if G_UNLIKELY (sigaction (SIGTERM, &oldterm, NULL) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "TERM", g_strerror (errno)); \
+ \
+ if G_UNLIKELY (sigaction (SIGINT, &oldint, NULL) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "INT", g_strerror (errno)); \
+ \
+ if G_UNLIKELY (sigaction (SIGHUP, &oldhup, NULL) < 0) \
+ g_critical (_("%s: Error setting up %s signal handler: %s"), \
+ "SETUP_INTERRUPTS_FOR_TERM", "HUP", g_strerror (errno));
+
+GdmHostent *
+gdm_gethostbyname (const char *name)
+{
+ struct addrinfo hints;
+ /* static because of Setjmp */
+ static struct addrinfo *result;
+
+ SETUP_INTERRUPTS_FOR_TERM_DECLS
+
+ /* The cached address */
+ static GdmHostent *he = NULL;
+ static time_t last_time = 0;
+ static char *cached_hostname = NULL;
+
+ if (cached_hostname != NULL &&
+ strcmp (cached_hostname, name) == 0) {
+ /* Don't check more then every 60 seconds */
+ if (last_time + 60 > time (NULL))
+ return gdm_hostent_copy (he);
+ }
+
+ SETUP_INTERRUPTS_FOR_TERM_SETUP
+
+ if (Setjmp (signal_jumpback) == 0) {
+ do_jumpback = TRUE;
+
+ /* Find client hostname */
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ if (result) {
+ freeaddrinfo (result);
+ result = NULL;
+ }
+
+ getaddrinfo (name, NULL, &hints, &result);
+ do_jumpback = FALSE;
+ } else {
+ /* Here we got interrupted */
+ result = NULL;
+ }
+
+ SETUP_INTERRUPTS_FOR_TERM_TEARDOWN
+
+ g_free (cached_hostname);
+ cached_hostname = g_strdup (name);
+
+ gdm_hostent_free (he);
+
+ he = fillout_addrinfo (result, NULL, name);
+
+ last_time = time (NULL);
+ return gdm_hostent_copy (he);
+}
+
+GdmHostent *
+gdm_gethostbyaddr (struct sockaddr_storage *ia)
+{
+ struct addrinfo hints;
+ /* static because of Setjmp */
+ static struct addrinfo *result = NULL;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ static struct in6_addr cached_addr6;
+
+ SETUP_INTERRUPTS_FOR_TERM_DECLS
+
+ /* The cached address */
+ static GdmHostent *he = NULL;
+ static time_t last_time = 0;
+ static struct in_addr cached_addr;
+
+ if (last_time != 0) {
+ if ((ia->ss_family == AF_INET6) && (memcmp (cached_addr6.s6_addr, ((struct sockaddr_in6 *) ia)->sin6_addr.s6_addr, sizeof (struct in6_addr)) == 0)) {
+ /* Don't check more then every 60 seconds */
+ if (last_time + 60 > time (NULL))
+ return gdm_hostent_copy (he);
+ } else if (ia->ss_family == AF_INET) {
+ if (memcmp (&cached_addr, &(((struct sockaddr_in *)ia)->sin_addr), sizeof (struct in_addr)) == 0) {
+ /* Don't check more then every 60 seconds */
+ if (last_time + 60 > time (NULL))
+ return gdm_hostent_copy (he);
+ }
+ }
+ }
+
+ SETUP_INTERRUPTS_FOR_TERM_SETUP
+
+ if (Setjmp (signal_jumpback) == 0) {
+ do_jumpback = TRUE;
+
+ /* Find client hostname */
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ if (result) {
+ freeaddrinfo (result);
+ result = NULL;
+ }
+
+ if (ia->ss_family == AF_INET6) {
+ char buffer6[INET6_ADDRSTRLEN];
+
+ inet_ntop (AF_INET6, &((struct sockaddr_in6 *)ia)->sin6_addr, buffer6, sizeof (buffer6));
+
+ /*
+ * In the case of IPv6 mapped address strip the
+ * ::ffff: and lookup as an IPv4 address
+ */
+ if (strncmp (buffer6, "::ffff:", 7) == 0) {
+ char *temp= (buffer6 + 7);
+ strcpy (buffer6, temp);
+ }
+ getaddrinfo (buffer6, NULL, &hints, &result);
+
+ } else if (ia->ss_family == AF_INET) {
+ char buffer[INET_ADDRSTRLEN];
+
+ inet_ntop (AF_INET, &((struct sockaddr_in *)ia)->sin_addr, buffer, sizeof (buffer));
+
+ getaddrinfo (buffer, NULL, &hints, &result);
+ }
+
+ do_jumpback = FALSE;
+ } else {
+ /* Here we got interrupted */
+ result = NULL;
+ }
+
+ SETUP_INTERRUPTS_FOR_TERM_TEARDOWN
+
+ if (ia->ss_family == AF_INET6) {
+ memcpy (cached_addr6.s6_addr, ((struct sockaddr_in6 *)ia)->sin6_addr.s6_addr, sizeof (struct in6_addr));
+ memset (&sin6, 0, sizeof (sin6));
+ memcpy (sin6.sin6_addr.s6_addr, cached_addr6.s6_addr, sizeof (struct in6_addr));
+ sin6.sin6_family = AF_INET6;
+ he = fillout_addrinfo (result, (struct sockaddr *)&sin6, NULL);
+ }
+ else if (ia->ss_family == AF_INET) {
+ memcpy (&(cached_addr.s_addr), &(((struct sockaddr_in *)ia)->sin_addr.s_addr), sizeof (struct in_addr));
+ memset (&sin, 0, sizeof (sin));
+ memcpy (&sin.sin_addr, &cached_addr, sizeof (struct in_addr));
+ sin.sin_family = AF_INET;
+ he = fillout_addrinfo (result, (struct sockaddr *)&sin, NULL);
}
- return FALSE;
+ last_time = time (NULL);
+ return gdm_hostent_copy (he);
+}
+
+GdmHostent *
+gdm_hostent_copy (GdmHostent *he)
+{
+ GdmHostent *cpy;
+
+ if (he == NULL)
+ return NULL;
+
+ cpy = g_new0 (GdmHostent, 1);
+ cpy->not_found = he->not_found;
+ cpy->hostname = g_strdup (he->hostname);
+ if (he->addr_count == 0) {
+ cpy->addr_count = 0;
+ cpy->addrs = NULL;
+ } else {
+ cpy->addr_count = he->addr_count;
+ cpy->addrs = g_new0 (struct sockaddr_storage, he->addr_count);
+ memcpy (cpy->addrs, he->addrs, sizeof (struct sockaddr_storage) * he->addr_count);
+ }
+ return cpy;
}
void
-gdm_address_get_info (struct sockaddr_storage *ss,
- char **hostp,
- char **servp)
+gdm_hostent_free (GdmHostent *he)
{
- char host [NI_MAXHOST];
- char serv [NI_MAXSERV];
+ if (he == NULL)
+ return;
+ g_free (he->hostname);
+ he->hostname = NULL;
+
+ g_free (he->addrs);
+ he->addrs = NULL;
+ he->addr_count = 0;
+
+ g_free (he);
+}
+
- host [0] = '\0';
- serv [0] = '\0';
- getnameinfo ((const struct sockaddr *)ss,
- sizeof (struct sockaddr_storage),
- host, sizeof (host),
- serv, sizeof (serv),
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (servp != NULL) {
- *servp = g_strdup (serv);
+/* Like fopen with "w" */
+FILE *
+gdm_safe_fopen_w (const char *file, mode_t perm)
+{
+ int fd;
+ FILE *ret;
+ VE_IGNORE_EINTR (g_unlink (file));
+ do {
+ errno = 0;
+ fd = open (file, O_EXCL|O_CREAT|O_TRUNC|O_WRONLY
+#ifdef O_NOCTTY
+ |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+ |O_NOFOLLOW
+#endif
+ , perm);
+ } while G_UNLIKELY (errno == EINTR);
+ if (fd < 0)
+ return NULL;
+ VE_IGNORE_EINTR (ret = fdopen (fd, "w"));
+ return ret;
+}
+
+/* Like fopen with "a+" */
+FILE *
+gdm_safe_fopen_ap (const char *file, mode_t perm)
+{
+ int fd;
+ FILE *ret;
+
+ if (g_access (file, F_OK) == 0) {
+ do {
+ errno = 0;
+ fd = open (file, O_APPEND|O_RDWR
+#ifdef O_NOCTTY
+ |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+ |O_NOFOLLOW
+#endif
+ );
+ } while G_UNLIKELY (errno == EINTR);
+ } else {
+ /* Doesn't exist, open with O_EXCL */
+ do {
+ errno = 0;
+ fd = open (file, O_EXCL|O_CREAT|O_RDWR
+#ifdef O_NOCTTY
+ |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+ |O_NOFOLLOW
+#endif
+ , perm);
+ } while G_UNLIKELY (errno == EINTR);
}
- if (hostp != NULL) {
- *hostp = g_strdup (host);
+ if (fd < 0)
+ return NULL;
+ VE_IGNORE_EINTR (ret = fdopen (fd, "a+"));
+ return ret;
+}
+
+void
+gdm_fd_set_close_on_exec (int fd)
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFD, 0);
+ if (flags < 0) {
+ return;
}
+
+ flags |= FD_CLOEXEC;
+
+ fcntl (fd, F_SETFD, flags);
}
/**
@@ -172,8 +800,9 @@ ve_first_word (const char *s)
return ret;
}
-gboolean
-ve_first_word_executable (const char *s, gboolean only_existance)
+static gboolean
+ve_first_word_executable (const char *s,
+ gboolean only_existance)
{
char *bin = ve_first_word (s);
if (bin == NULL)
diff --git a/common/gdm-common.h b/common/gdm-common.h
index c189d41a..d509271f 100644
--- a/common/gdm-common.h
+++ b/common/gdm-common.h
@@ -38,26 +38,105 @@
G_BEGIN_DECLS
+#define ve_string_empty(x) ((x)==NULL||(x)[0]=='\0')
+#define ve_sure_string(x) ((x)!=NULL?(x):"")
+#define VE_IGNORE_EINTR(expr) \
+ do { \
+ errno = 0; \
+ expr; \
+ } while G_UNLIKELY (errno == EINTR);
+
+#define NEVER_FAILS_seteuid(uid) \
+ { int r = 0; \
+ if (geteuid () != uid) \
+ r = seteuid (uid); \
+ if G_UNLIKELY (r != 0) \
+ g_error ("GDM file %s: line %d (%s): Cannot run seteuid to %d: %s", \
+ __FILE__, \
+ __LINE__, \
+ G_GNUC_PRETTY_FUNCTION, \
+ (int)uid, \
+ strerror (errno)); }
+#define NEVER_FAILS_setegid(gid) \
+ { int r = 0; \
+ if (getegid () != gid) \
+ r = setegid (gid); \
+ if G_UNLIKELY (r != 0) \
+ g_error ("GDM file %s: line %d (%s): Cannot run setegid to %d: %s", \
+ __FILE__, \
+ __LINE__, \
+ G_GNUC_PRETTY_FUNCTION, \
+ (int)gid, \
+ strerror (errno)); }
+
+/* first goes to euid-root and then sets the egid and euid, to make sure
+ * this succeeds */
+#define NEVER_FAILS_root_set_euid_egid(uid,gid) \
+ { NEVER_FAILS_seteuid (0); \
+ NEVER_FAILS_setegid (gid); \
+ if (uid != 0) { NEVER_FAILS_seteuid (uid); } }
+
+
+/* like fopen with "w" but unlinks and uses O_EXCL */
+FILE * gdm_safe_fopen_w (const char *file,
+ mode_t perm);
+/* like fopen with "a+" and uses O_EXCL and O_NOFOLLOW */
+FILE * gdm_safe_fopen_ap (const char *file,
+ mode_t perm);
+
+
+typedef struct {
+ gboolean not_found; /* hostname below set to fallback,
+ as gethostbyaddr/name failed */
+ char *hostname; /* never a bogus dot, if
+ invalid/unknown, then set to the
+ ip address in string form */
+
+ struct sockaddr_storage *addrs;
+ int addr_count;
+} GdmHostent;
+
+GdmHostent * gdm_gethostbyname (const char *name);
+
+GdmHostent *gdm_gethostbyaddr (struct sockaddr_storage *ia);
+GdmHostent * gdm_hostent_copy (GdmHostent *he);
+void gdm_hostent_free (GdmHostent *he);
+
+/* This is for race free forks */
+void gdm_sigchld_block_push (void);
+void gdm_sigchld_block_pop (void);
+void gdm_sigterm_block_push (void);
+void gdm_sigterm_block_pop (void);
+void gdm_sigusr2_block_push (void);
+void gdm_sigusr2_block_pop (void);
+
+void gdm_fdprintf (int fd, const gchar *format, ...) G_GNUC_PRINTF (2, 3);
+int gdm_fdgetc (int fd);
+char *gdm_fdgets (int fd);
+
+void gdm_signal_ignore (int signal);
+void gdm_signal_default (int signal);
+
+void gdm_close_all_descriptors (int from, int except, int except2);
+
+int gdm_open_dev_null (mode_t mode);
+
+/* somewhat like g_build_filename, but does somet hing like
+ * <dir> "/" <name> <extension>
+ */
+char * gdm_make_filename (const char *dir,
+ const char *name,
+ const char *extension);
-gboolean gdm_address_equal (struct sockaddr_storage *sa,
- struct sockaddr_storage *sb);
-gboolean gdm_address_is_loopback (struct sockaddr_storage *sa);
-void gdm_address_get_info (struct sockaddr_storage *sa,
- char **host,
- char **port);
+void gdm_fd_set_close_on_exec (int fd);
void ve_clearenv (void);
char * ve_first_word (const char *s);
-gboolean ve_first_word_executable (const char *s,
- gboolean only_existance);
/* Gets the first existing command out of a list separated by semicolons */
char * ve_get_first_working_command (const char *list,
gboolean only_existance);
-#define ve_string_empty(x) ((x)==NULL||(x)[0]=='\0')
-#define ve_sure_string(x) ((x)!=NULL?(x):"")
-
/* These two functions will ALWAYS return a non-NULL string,
* if there is an error, they return the unconverted string */
char * ve_locale_to_utf8 (const char *str);
@@ -74,12 +153,6 @@ pid_t ve_waitpid_no_signal (pid_t pid, int *status, int options);
/* Testing for existance of a certain locale */
gboolean ve_locale_exists (const char *loc);
-#define VE_IGNORE_EINTR(expr) \
- do { \
- errno = 0; \
- expr; \
- } while G_UNLIKELY (errno == EINTR);
-
G_END_DECLS
#endif /* _GDM_COMMON_H */
diff --git a/configure.ac b/configure.ac
index 11186a22..7e4de566 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,7 +48,7 @@ dnl
AC_ARG_ENABLE(console-helper,
[ --enable-console-helper=[auto/no/yes] Enable PAM console helper [default=auto]],,
enable_console_helper=auto)
-
+
AC_ARG_ENABLE(authentication-scheme,
[ --enable-authentication-scheme=[auto/pam/crypt/shadow] Choose a specific
authentication scheme [default=auto]],,
@@ -813,14 +813,37 @@ fi
use_console_kit=no
if test "x$with_console_kit" != "xno" ; then
use_console_kit=yes
- PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= $DBUS_REQUIRED)
AC_DEFINE(WITH_CONSOLE_KIT, 1, [Define to enable ConsoleKit support])
fi
AM_CONDITIONAL(WITH_CONSOLE_KIT, test x$use_console_kit = xyes)
AC_SUBST(WITH_CONSOLE_KIT)
+
+dnl ---------------------------------------------------------------------------
+dnl - D-Bus
+dnl ---------------------------------------------------------------------------
+
+PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= $DBUS_REQUIRED)
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
+dnl ---------------------------------------------------------------------------
+dnl - Are we specifying a different dbus root ?
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(dbus-sys,
+ [AC_HELP_STRING([--with-dbus-sys=<dir>],
+ [where D-BUS system.d directory is])])
+AC_ARG_WITH(dbus-services,
+ [AC_HELP_STRING([--with-dbus-services=<dir>],
+ [where D-BUS services directory is])])
+if ! test -z "$with_dbus_sys" ; then
+ DBUS_SYS_DIR="$with_dbus_sys"
+else
+ DBUS_SYS_DIR="$sysconfdir/dbus-1/system.d"
+fi
+AC_SUBST(DBUS_SYS_DIR)
+
+
#
# Define some variables to represent the directories we use.
#
@@ -1273,9 +1296,10 @@ pixmaps/Makefile
pixmaps/16x16/Makefile
pixmaps/32x32/Makefile
pixmaps/48x48/Makefile
+data/Makefile
config/Makefile
-po/Makefile.in
common/Makefile
+po/Makefile.in
docs/Makefile
docs/de/Makefile
docs/es/Makefile
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3ccb4b61..02fcef7d 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -26,48 +26,102 @@ INCLUDES = \
-DLANG_CONFIG_FILE=\"$(LANG_CONFIG_FILE)\" \
$(GNOME_INCLUDEDIR) \
-DGREETERTHEMEDIR=\""$(datadir)/gdm/themes"\" \
+ $(DBUS_CFLAGS) \
$(NULL)
-sbin_PROGRAMS = gdm-binary \
+BUILT_SOURCES = \
+ gdm-slave-glue.h \
+ gdm-manager-glue.h \
+ gdm-display-glue.h \
+ gdm-xdmcp-display-glue.h \
+ gdm-static-display-glue.h \
$(NULL)
-gdm_binary_SOURCES = \
- gdm.c \
- gdm.h \
- gdm-daemon-config.c \
- gdm-daemon-config.h \
- gdm-daemon-config-entries.h \
- gdm-daemon-config-keys.h \
- gdm-socket-protocol.h \
- display.c \
- display.h \
+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-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
+ dbus-binding-tool --prefix=gdm_xdmcp_display --mode=glib-server --output=gdm-xdmcp-display-glue.h gdm-xdmcp-display.xml
+gdm-static-display-glue.h: gdm-static-display.xml Makefile.am
+ dbus-binding-tool --prefix=gdm_static_display --mode=glib-server --output=gdm-static-display-glue.h gdm-static-display.xml
+
+libexec_PROGRAMS = \
+ gdm-slave \
+ $(NULL)
+
+gdm_slave_SOURCES = \
+ slave-main.c \
+ gdm-greeter.c \
+ gdm-greeter.h \
+ gdm-server.c \
+ gdm-server.h \
+ gdm-slave.c \
+ gdm-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 = \
+ $(EXTRA_DAEMON_LIBS) \
+ $(NULL)
+
+gdm_slave_LDADD = \
+ $(DAEMON_LIBS) \
+ $(INTLLIBS) \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS) \
+ $(GDK_LIBS) \
+ $(top_builddir)/common/libgdmcommon.a \
+ $(X_LIBS) \
+ $(XINERAMA_LIBS) \
+ $(DBUS_LIBS) \
+ -lXau \
+ -lX11 \
+ -lXext \
+ $(NULL)
+
+sbin_PROGRAMS = \
+ gdm-binary \
+ $(NULL)
+
+gdm_binary_SOURCES = \
+ gdm.h \
+ main.c \
+ gdm-master-config.c \
+ gdm-master-config.h \
+ gdm-daemon-config-entries.h \
+ gdm-display-store.c \
+ gdm-display-store.h \
+ gdm-display.c \
+ gdm-display.h \
+ gdm-xdmcp-display.c \
+ gdm-xdmcp-display.h \
+ gdm-static-display.c \
+ gdm-static-display.h \
+ gdm-manager.c \
+ gdm-manager.h \
+ gdm-slave-proxy.c \
+ gdm-slave-proxy.h \
+ gdm-daemon-config-keys.h \
+ gdm-socket-protocol.h \
+ auth.c \
+ auth.h \
fstype.c \
- slave.c \
- slave.h \
- server.c \
server.h \
- misc.c \
- misc.h \
- auth.c \
- auth.h \
cookie.c \
cookie.h \
- xdmcp.c \
- xdmcp.h \
choose.c \
choose.h \
filecheck.c \
filecheck.h \
md5.c \
md5.h \
- @VRFY@.c \
- verify.h \
- errorgui.c \
- errorgui.h \
- gdm-net.c \
- gdm-net.h \
- getvt.c \
- getvt.h \
$(NULL)
XDMCP_SOURCES = \
@@ -109,6 +163,7 @@ gdm_binary_LDADD = \
$(X_LIBS) \
$(XINERAMA_LIBS) \
$(XDMCP_LIBS) \
+ $(DBUS_LIBS) \
-lXau \
-lX11 \
-lXext \
@@ -116,14 +171,25 @@ gdm_binary_LDADD = \
if WITH_CONSOLE_KIT
gdm_binary_SOURCES += $(CONSOLE_KIT_SOURCES)
-gdm_binary_LDADD += $(DBUS_LIBS)
-INCLUDES += $(DBUS_CFLAGS)
endif
-sbin_SCRIPTS = gdm
-CLEANFILES = gdm
+sbin_SCRIPTS = \
+ gdm \
+ $(NULL)
gdm: $(srcdir)/gdm.in
sed -e 's,[@]sbindir[@],$(sbindir),g' <$(srcdir)/gdm.in >gdm
-EXTRA_DIST = gdm.in
+CLEANFILES = \
+ gdm \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+EXTRA_DIST = \
+ gdm.in \
+ gdm-slave.xml \
+ gdm-manager.xml \
+ gdm-display.xml \
+ gdm-xdmcp-display.xml \
+ gdm-static-display.xml \
+ $(NULL)
diff --git a/daemon/auth.c b/daemon/auth.c
index 0927c288..4b3e889f 100644
--- a/daemon/auth.c
+++ b/daemon/auth.c
@@ -34,17 +34,17 @@
#include <errno.h>
#include <X11/Xauth.h>
+
+#include <glib.h>
#include <glib/gi18n.h>
-#include "gdm.h"
#include "cookie.h"
-#include "misc.h"
#include "filecheck.h"
#include "auth.h"
#include "gdm-common.h"
#include "gdm-log.h"
-#include "gdm-daemon-config.h"
+#include "gdm-master-config.h"
/* Ensure we know about FamilyInternetV6 even if what we're compiling
against doesn't */
@@ -57,41 +57,17 @@
/* Local prototypes */
static FILE *gdm_auth_purge (GdmDisplay *d, FILE *af, gboolean remove_when_empty);
-static void
-display_add_error (GdmDisplay *d)
-{
- if (errno != 0)
- gdm_error (_("%s: Could not write new authorization entry: %s"),
- "add_auth_entry", strerror (errno));
- else
- gdm_error (_("%s: Could not write new authorization entry. "
- "Possibly out of diskspace"),
- "add_auth_entry");
- if (d->attached) {
- char *s = g_strdup_printf
- (C_(N_("GDM could not write a new authorization "
- "entry to disk. Possibly out of diskspace.%s%s")),
- errno != 0 ? " Error: " : "",
- errno != 0 ? strerror (errno) : "");
- gdm_text_message_dialog (s);
- g_free (s);
- }
-}
-
-static gboolean
-add_auth_entry (GdmDisplay *d,
- GSList **authlist,
- FILE *af,
- FILE *af2,
- unsigned short family,
- const char *addr,
- int addrlen)
+gboolean
+gdm_auth_add_entry (int display_num,
+ const char *bcookie,
+ GSList **authlist,
+ FILE *af,
+ unsigned short family,
+ const char *addr,
+ int addrlen)
{
Xauth *xa;
- gchar *dispnum;
-
- if G_UNLIKELY (!d)
- return FALSE;
+ char *dispnum;
xa = malloc (sizeof (Xauth));
@@ -113,7 +89,7 @@ add_auth_entry (GdmDisplay *d,
xa->address_length = addrlen;
}
- dispnum = g_strdup_printf ("%d", d->dispnum);
+ dispnum = g_strdup_printf ("%d", display_num);
xa->number = strdup (dispnum);
xa->number_length = strlen (dispnum);
g_free (dispnum);
@@ -128,7 +104,8 @@ add_auth_entry (GdmDisplay *d,
free (xa);
return FALSE;
}
- memcpy (xa->data, d->bcookie, 16);
+
+ memcpy (xa->data, bcookie, 16);
xa->data_length = 16;
if (af != NULL) {
@@ -139,21 +116,17 @@ add_auth_entry (GdmDisplay *d,
free (xa->name);
free (xa->address);
free (xa);
- display_add_error (d);
- return FALSE;
- }
- if (af2 != NULL) {
- errno = 0;
- if G_UNLIKELY ( ! XauWriteAuth (af2, xa)) {
- free (xa->data);
- free (xa->number);
- free (xa->name);
- free (xa->address);
- free (xa);
- display_add_error (d);
- return FALSE;
+ if (errno != 0) {
+ g_warning (_("%s: Could not write new authorization entry: %s"),
+ "add_auth_entry", g_strerror (errno));
+ } else {
+ g_warning (_("%s: Could not write new authorization entry. "
+ "Possibly out of diskspace"),
+ "add_auth_entry");
}
+
+ return FALSE;
}
}
@@ -162,152 +135,23 @@ add_auth_entry (GdmDisplay *d,
return TRUE;
}
-/**
- * gdm_auth_secure_display:
- * @d: Pointer to a GdmDisplay struct
- *
- * Create authentication cookies for local and remote displays.
- *
- * Returns TRUE on success and FALSE on error.
- */
-
gboolean
-gdm_auth_secure_display (GdmDisplay *d)
+gdm_auth_add_entry_for_display (int display_num,
+ const char *bcookie,
+ GSList **authlist,
+ FILE *af)
{
- FILE *af, *af_gdm;
- int closeret;
-
- if G_UNLIKELY (!d)
- return FALSE;
-
- umask (022);
-
- gdm_debug ("gdm_auth_secure_display: Setting up access for %s", d->name);
-
- g_free (d->authfile);
- d->authfile = NULL;
- g_free (d->authfile_gdm);
- d->authfile_gdm = NULL;
-
- if (d->server_uid != 0) {
- int authfd;
-
- /* Note, nested display can't use the GDM_KEY_SERV_AUTHDIR unless
- * running as root, which is rare anyway. */
-
- d->authfile = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_USER_AUTHDIR_FALLBACK), ".gdmXXXXXX", NULL);
-
- umask (077);
- authfd = g_mkstemp (d->authfile);
- umask (022);
-
- if G_UNLIKELY (authfd == -1) {
- gdm_error (_("%s: Could not make new cookie file in %s"),
- "gdm_auth_secure_display", gdm_daemon_config_get_value_string (GDM_KEY_USER_AUTHDIR_FALLBACK));
- g_free (d->authfile);
- d->authfile = NULL;
- return FALSE;
- }
-
- /* Make it owned by the user that nested display is started as */
- fchown (authfd, d->server_uid, -1);
-
- VE_IGNORE_EINTR (af = fdopen (authfd, "w"));
-
- if G_UNLIKELY (af == NULL) {
- g_free (d->authfile);
- d->authfile = NULL;
- return FALSE;
- }
-
- /* Make another authfile since the greeter can't read the server/user
- * readable file */
- d->authfile_gdm = gdm_make_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), d->name, ".Xauth");
- af_gdm = gdm_safe_fopen_w (d->authfile_gdm, 0644);
-
- if G_UNLIKELY (af_gdm == NULL) {
- gdm_error (_("%s: Cannot safely open %s"),
- "gdm_auth_secure_display",
- d->authfile_gdm);
-
- g_free (d->authfile_gdm);
- d->authfile_gdm = NULL;
- g_free (d->authfile);
- d->authfile = NULL;
- VE_IGNORE_EINTR (fclose (af));
- return FALSE;
- }
- } else {
- /* gdm and xserver authfile can be the same, server will run as root */
- d->authfile = gdm_make_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), d->name, ".Xauth");
- af = gdm_safe_fopen_w (d->authfile, 0644);
-
- if G_UNLIKELY (af == NULL) {
- gdm_error (_("%s: Cannot safely open %s"),
- "gdm_auth_secure_display",
- d->authfile);
-
- g_free (d->authfile);
- d->authfile = NULL;
- return FALSE;
- }
-
- af_gdm = NULL;
- }
-
- /* If this is a local display the struct hasn't changed and we
- * have to eat up old authentication cookies before baking new
- * ones... */
- if (SERVER_IS_LOCAL (d) && d->auths) {
- gdm_auth_free_auth_list (d->auths);
- d->auths = NULL;
-
- g_free (d->cookie);
- d->cookie = NULL;
- g_free (d->bcookie);
- d->bcookie = NULL;
- }
-
- /* Create new random cookie */
- gdm_cookie_generate (&d->cookie, &d->bcookie);
-
- /* reget local host if local as it may have changed */
- if (SERVER_IS_LOCAL (d)) {
- char hostname[1024];
-
- hostname[1023] = '\0';
- if G_LIKELY (gethostname (hostname, 1023) == 0) {
- g_free (d->hostname);
- d->hostname = g_strdup (hostname);
- }
- }
-
- if ( ! add_auth_entry (d, &(d->auths), af, af_gdm, FamilyWild, NULL, 0))
- return FALSE;
-
- gdm_debug ("gdm_auth_secure_display: Setting up access");
-
- VE_IGNORE_EINTR (closeret = fclose (af));
- if G_UNLIKELY (closeret < 0) {
- display_add_error (d);
- return FALSE;
- }
- if (af_gdm != NULL) {
- VE_IGNORE_EINTR (closeret = fclose (af_gdm));
- if G_UNLIKELY (closeret < 0) {
- display_add_error (d);
- return FALSE;
- }
- }
- g_setenv ("XAUTHORITY", GDM_AUTHFILE (d), TRUE);
-
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG))
- gdm_debug ("gdm_auth_secure_display: Setting up access for %s - %d entries",
- d->name, g_slist_length (d->auths));
-
- return TRUE;
+ gdm_auth_add_entry (display_num,
+ bcookie,
+ authlist,
+ af,
+ FamilyWild,
+ NULL,
+ 0);
}
+#if 0
+
#define SA(__s) ((struct sockaddr *) __s)
#define SIN(__s) ((struct sockaddr_in *) __s)
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
@@ -352,7 +196,7 @@ get_local_auths (GdmDisplay *d)
if G_UNLIKELY (!d)
return NULL;
- if (SERVER_IS_LOCAL (d)) {
+ if (gdm_display_is_local (d)) {
char hostname[1024];
/* reget local host if local as it may have changed */
@@ -391,7 +235,7 @@ get_local_auths (GdmDisplay *d)
/* local machine but not local if you get my meaning, add
* the host gotten by gethostname as well if it's different
* since the above is probably localhost */
- if ( ! SERVER_IS_LOCAL (d)) {
+ if ( ! gdm_display_is_local (d)) {
char hostname[1024];
hostname[1023] = '\0';
@@ -418,7 +262,7 @@ get_local_auths (GdmDisplay *d)
gdm_debug ("get_local_auths: Setting up network access");
- if ( ! SERVER_IS_LOCAL (d)) {
+ if ( ! gdm_display_is_local (d)) {
/* we should write out an entry for d->addr since
possibly it is not in d->addrs */
@@ -468,7 +312,7 @@ get_local_auths (GdmDisplay *d)
}
/* if local server add loopback */
- if (SERVER_IS_LOCAL (d) && ! added_lo && ! d->tcp_disallowed) {
+ if (gdm_display_is_local (d) && ! added_lo && ! d->tcp_disallowed) {
struct sockaddr_storage *lo_ss = NULL;
/* FIXME: get loobback ss */
if (! add_auth_entry_for_addr (d, &auths, lo_ss)) {
@@ -476,9 +320,8 @@ get_local_auths (GdmDisplay *d)
}
}
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG))
- gdm_debug ("get_local_auths: Setting up access for %s - %d entries",
- d->name, g_slist_length (auths));
+ g_debug ("get_local_auths: Setting up access for %s - %d entries",
+ d->name, g_slist_length (auths));
return auths;
@@ -1005,3 +848,4 @@ gdm_auth_free_auth_list (GSList *list)
g_slist_free (list);
}
+#endif
diff --git a/daemon/auth.h b/daemon/auth.h
index f01ebcbf..0f84dde5 100644
--- a/daemon/auth.h
+++ b/daemon/auth.h
@@ -19,17 +19,33 @@
#ifndef GDM_AUTH_H
#define GDM_AUTH_H
-#include "gdm.h"
+#include "gdm-display.h"
-gboolean gdm_auth_secure_display (GdmDisplay *d);
-gboolean gdm_auth_user_add (GdmDisplay *d, uid_t user, const char *homedir);
-void gdm_auth_user_remove (GdmDisplay *d, uid_t user);
+G_BEGIN_DECLS
+
+gboolean gdm_auth_add_entry_for_display (int display_num,
+ const char *bcookie,
+ GSList **authlist,
+ FILE *af);
+gboolean gdm_auth_add_entry (int display_num,
+ const char *bcookie,
+ GSList **authlist,
+ FILE *af,
+ unsigned short family,
+ const char *addr,
+ int addrlen);
+
+gboolean gdm_auth_user_add (GdmDisplay *d,
+ uid_t user,
+ const char *homedir);
+void gdm_auth_user_remove (GdmDisplay *d,
+ uid_t user);
/* Call XSetAuthorization */
void gdm_auth_set_local_auth (GdmDisplay *d);
-void gdm_auth_free_auth_list (GSList *list);
+void gdm_auth_free_auth_list (GSList *list);
-#endif /* GDM_AUTH_H */
+G_END_DECLS
-/* EOF */
+#endif /* GDM_AUTH_H */
diff --git a/daemon/choose.c b/daemon/choose.c
index bd08b10c..a460b31e 100644
--- a/daemon/choose.c
+++ b/daemon/choose.c
@@ -40,14 +40,13 @@
#include <fcntl.h>
#include <string.h>
-#include "gdm.h"
-#include "misc.h"
#include "choose.h"
-#include "xdmcp.h"
+#include "gdm-address.h"
#include "gdm-common.h"
#include "gdm-log.h"
-#include "gdm-daemon-config.h"
+#include "gdm-master-config.h"
+#include "gdm-daemon-config-entries.h"
#include "gdm-socket-protocol.h"
@@ -86,8 +85,8 @@ remove_oldest_pending (void)
#endif
static gboolean
-get_first_address_for_node (const char *node,
- struct sockaddr_storage **sa)
+get_first_address_for_node (const char *node,
+ GdmAddress **address)
{
struct addrinfo hints;
struct addrinfo *ai_list;
@@ -122,8 +121,8 @@ get_first_address_for_node (const char *node,
}
if (ai != NULL) {
- if (sa != NULL) {
- *sa = g_memdup (ai->ai_addr, ai->ai_addrlen);
+ if (address != NULL) {
+ *address = gdm_address_new_from_sockaddr_storage ((struct sockaddr_storage *)ai->ai_addr);
}
}
@@ -132,19 +131,33 @@ get_first_address_for_node (const char *node,
return found;
}
+static int
+get_config_int (int id)
+{
+ GdmDaemonConfig *dc;
+ int val;
+
+ dc = gdm_daemon_config_new ();
+ gdm_daemon_config_get_int_for_id (dc, id, &val);
+
+ g_object_unref (dc);
+
+ return val;
+}
+
gboolean
gdm_choose_data (const char *data)
{
- int id;
- struct sockaddr_storage *sa;
- GSList *li;
- char *msg;
- char *p;
- char *host;
- gboolean ret;
+ int id;
+ GdmAddress *address;
+ GSList *li;
+ char *msg;
+ char *p;
+ char *host;
+ gboolean ret;
msg = g_strdup (data);
- sa = NULL;
+ address = NULL;
ret = FALSE;
p = strtok (msg, " ");
@@ -163,28 +176,28 @@ gdm_choose_data (const char *data)
goto out;
}
- if (! get_first_address_for_node (p, &sa)) {
+ if (! get_first_address_for_node (p, &address)) {
goto out;
}
- gdm_address_get_info (sa, &host, NULL);
- gdm_debug ("gdm_choose_data: got indirect id: %d address: %s",
- id,
- host);
+ gdm_address_get_numeric_info (address, &host, NULL);
+ g_debug ("gdm_choose_data: got indirect id: %d address: %s",
+ id,
+ host);
g_free (host);
for (li = indirect; li != NULL; li = li->next) {
GdmIndirectDisplay *idisp = li->data;
if (idisp->id == id) {
/* whack the oldest if more then allowed */
- while (ipending >= gdm_daemon_config_get_value_int (GDM_KEY_MAX_INDIRECT) &&
+ while (ipending >= get_config_int (GDM_ID_MAX_INDIRECT) &&
remove_oldest_pending ())
;
idisp->acctime = time (NULL);
g_free (idisp->chosen_host);
- idisp->chosen_host = g_memdup (sa, sizeof (struct sockaddr_storage));
+ idisp->chosen_host = gdm_address_copy (address);
/* Now this display is pending */
ipending++;
@@ -194,7 +207,7 @@ gdm_choose_data (const char *data)
}
}
out:
- g_free (sa);
+ gdm_address_free (address);
g_free (msg);
return ret;
@@ -202,13 +215,12 @@ gdm_choose_data (const char *data)
GdmIndirectDisplay *
-gdm_choose_indirect_alloc (struct sockaddr_storage *clnt_sa)
+gdm_choose_indirect_alloc (GdmAddress *address)
{
GdmIndirectDisplay *id;
- char *host;
+ char *host;
- if (clnt_sa == NULL)
- return NULL;
+ g_assert (address != NULL);
id = g_new0 (GdmIndirectDisplay, 1);
id->id = indirect_id++;
@@ -217,18 +229,18 @@ gdm_choose_indirect_alloc (struct sockaddr_storage *clnt_sa)
if (id->id == 0)
id->id = indirect_id++;
- id->dsp_sa = g_memdup (clnt_sa, sizeof (struct sockaddr_storage));
+ id->dsp_address = gdm_address_copy (address);
id->chosen_host = NULL;
id->acctime = 0;
indirect = g_slist_prepend (indirect, id);
- gdm_address_get_info (id->dsp_sa, &host, NULL);
+ gdm_address_get_numeric_info (id->dsp_address, &host, NULL);
- gdm_debug ("gdm_choose_display_alloc: display=%s, pending=%d ",
- host,
- ipending);
+ g_debug ("gdm_choose_display_alloc: display=%s, pending=%d ",
+ host,
+ ipending);
g_free (host);
return (id);
@@ -258,8 +270,8 @@ gdm_choose_indirect_dispose_empty_id (guint id)
}
GdmIndirectDisplay *
-gdm_choose_indirect_lookup_by_chosen (struct sockaddr_storage *chosen,
- struct sockaddr_storage *origin)
+gdm_choose_indirect_lookup_by_chosen (GdmAddress *chosen,
+ GdmAddress *origin)
{
GSList *li;
char *host;
@@ -270,21 +282,21 @@ gdm_choose_indirect_lookup_by_chosen (struct sockaddr_storage *chosen,
if (id != NULL &&
id->chosen_host != NULL &&
gdm_address_equal (id->chosen_host, chosen)) {
- if (gdm_address_equal (id->dsp_sa, origin)) {
+ if (gdm_address_equal (id->dsp_address, origin)) {
return id;
- } else if (gdm_address_is_loopback (id->dsp_sa) &&
+ } else if (gdm_address_is_loopback (id->dsp_address) &&
gdm_address_is_local (origin)) {
return id;
}
}
}
- gdm_address_get_info (chosen, &host, NULL);
+ gdm_address_get_numeric_info (chosen, &host, NULL);
- gdm_debug ("gdm_choose_indirect_lookup_by_chosen: Chosen %s host not found",
- host);
- gdm_debug ("gdm_choose_indirect_lookup_by_chosen: Origin was: %s",
- host);
+ g_debug ("gdm_choose_indirect_lookup_by_chosen: Chosen %s host not found",
+ host);
+ g_debug ("gdm_choose_indirect_lookup_by_chosen: Origin was: %s",
+ host);
g_free (host);
return NULL;
@@ -292,7 +304,7 @@ gdm_choose_indirect_lookup_by_chosen (struct sockaddr_storage *chosen,
GdmIndirectDisplay *
-gdm_choose_indirect_lookup (struct sockaddr_storage *clnt_sa)
+gdm_choose_indirect_lookup (GdmAddress *address)
{
GSList *li, *ilist;
GdmIndirectDisplay *id;
@@ -307,27 +319,27 @@ gdm_choose_indirect_lookup (struct sockaddr_storage *clnt_sa)
continue;
if (id->acctime > 0 &&
- curtime > id->acctime + gdm_daemon_config_get_value_int (GDM_KEY_MAX_WAIT_INDIRECT)) {
+ curtime > id->acctime + get_config_int (GDM_ID_MAX_WAIT_INDIRECT)) {
- gdm_address_get_info (clnt_sa, &host, NULL);
- gdm_debug ("gdm_choose_indirect_check: Disposing stale INDIRECT query from %s",
- host);
+ gdm_address_get_numeric_info (address, &host, NULL);
+ g_debug ("gdm_choose_indirect_check: Disposing stale INDIRECT query from %s",
+ host);
g_free (host);
gdm_choose_indirect_dispose (id);
continue;
}
- if (gdm_address_equal (id->dsp_sa, clnt_sa)) {
+ if (gdm_address_equal (id->dsp_address, address)) {
g_slist_free (ilist);
return id;
}
}
g_slist_free (ilist);
- gdm_address_get_info (clnt_sa, &host, NULL);
- gdm_debug ("gdm_choose_indirect_lookup: Host %s not found",
- host);
+ gdm_address_get_numeric_info (address, &host, NULL);
+ g_debug ("gdm_choose_indirect_lookup: Host %s not found",
+ host);
g_free (host);
return NULL;
@@ -348,16 +360,16 @@ gdm_choose_indirect_dispose (GdmIndirectDisplay *id)
ipending--;
id->acctime = 0;
- gdm_address_get_info (id->dsp_sa, &host, NULL);
- gdm_debug ("gdm_choose_indirect_dispose: Disposing %s",
+ gdm_address_get_numeric_info (id->dsp_address, &host, NULL);
+ g_debug ("gdm_choose_indirect_dispose: Disposing %s",
host);
g_free (host);
g_free (id->chosen_host);
id->chosen_host = NULL;
- g_free (id->dsp_sa);
- id->dsp_sa = NULL;
+ gdm_address_free (id->dsp_address);
+ id->dsp_address = NULL;
g_free (id);
}
diff --git a/daemon/choose.h b/daemon/choose.h
index 3fface4d..ea2fe87b 100644
--- a/daemon/choose.h
+++ b/daemon/choose.h
@@ -21,20 +21,20 @@
#ifndef CHOOSE_H
#define CHOOSE_H
-#include "gdm.h"
+#include "gdm-address.h"
typedef struct _GdmIndirectDisplay GdmIndirectDisplay;
struct _GdmIndirectDisplay {
- int id;
- struct sockaddr_storage* dsp_sa;
- struct sockaddr_storage* chosen_host;
- time_t acctime;
+ int id;
+ GdmAddress *dsp_address;
+ GdmAddress *chosen_host;
+ time_t acctime;
};
-GdmIndirectDisplay * gdm_choose_indirect_alloc (struct sockaddr_storage *clnt_sa);
-GdmIndirectDisplay * gdm_choose_indirect_lookup (struct sockaddr_storage *clnt_sa);
-GdmIndirectDisplay * gdm_choose_indirect_lookup_by_chosen (struct sockaddr_storage *chosen,
- struct sockaddr_storage *origin);
+GdmIndirectDisplay * gdm_choose_indirect_alloc (GdmAddress *address);
+GdmIndirectDisplay * gdm_choose_indirect_lookup (GdmAddress *address);
+GdmIndirectDisplay * gdm_choose_indirect_lookup_by_chosen (GdmAddress *chosen,
+ GdmAddress *origin);
void gdm_choose_indirect_dispose (GdmIndirectDisplay *id);
/* dispose of indirect display of id, if no host is set */
diff --git a/daemon/cookie.c b/daemon/cookie.c
index 55f9621b..35016fb0 100644
--- a/daemon/cookie.c
+++ b/daemon/cookie.c
@@ -44,7 +44,7 @@
#include "cookie.h"
#include "gdm-common.h"
-#include "gdm-daemon-config.h"
+#include "gdm-master-config.h"
#define MAXBUFFERSIZE 1024
diff --git a/daemon/cookie.h b/daemon/cookie.h
index 9342f037..cdede2b8 100644
--- a/daemon/cookie.h
+++ b/daemon/cookie.h
@@ -27,5 +27,3 @@ void gdm_cookie_generate (char **cookie,
void gdm_random_tick (void);
#endif /* GDM_COOKIE_H */
-
-/* EOF */
diff --git a/daemon/display.c b/daemon/display.c
index 311f5647..f02c7acd 100644
--- a/daemon/display.c
+++ b/daemon/display.c
@@ -43,10 +43,6 @@
#include "gdm-daemon-config.h"
/* External vars */
-extern GdmConnection *fifoconn;
-extern GdmConnection *pipeconn;
-extern GdmConnection *unixconn;
-extern int slave_fifo_pipe_fd; /* the slavepipe (like fifo) connection, this is the write end */
extern gint flexi_servers;
/**
@@ -371,17 +367,10 @@ gdm_display_manage (GdmDisplay *d)
d->slavepid = getpid ();
- gdm_connection_close (fifoconn);
- fifoconn = NULL;
- gdm_connection_close (pipeconn);
- pipeconn = NULL;
- gdm_connection_close (unixconn);
- unixconn = NULL;
-
gdm_log_shutdown ();
/* Close everything */
- gdm_close_all_descriptors (0 /* from */, fds[0] /* except */, slave_fifo_pipe_fd /* except2 */);
+ gdm_close_all_descriptors (0 /* from */, fds[0] /* except */, -1 /* except2 */);
/* No error checking here - if it's messed the best response
* is to ignore & try to continue */
diff --git a/daemon/display.h b/daemon/display.h
index f25373d5..8c2bfd8a 100644
--- a/daemon/display.h
+++ b/daemon/display.h
@@ -29,6 +29,32 @@ typedef struct _GdmDisplay GdmDisplay;
#include "gdm-net.h" /* for GdmConnection */
+/* DO NOTE USE 1, that's used as error if x connection fails usually */
+/* Note that there is no reason why these were a power of two, and note
+ * that they have to fit in 256 */
+/* These are the exit codes */
+#define DISPLAY_REMANAGE 2 /* Restart display */
+#define DISPLAY_ABORT 4 /* Houston, we have a problem */
+#define DISPLAY_REBOOT 8 /* Rebewt */
+#define DISPLAY_HALT 16 /* Halt */
+#define DISPLAY_SUSPEND 17 /* Suspend (don't use, use the interrupt) */
+#define DISPLAY_CHOSEN 20 /* successful chooser session,
+ restart display */
+#define DISPLAY_RUN_CHOOSER 30 /* Run chooser */
+#define DISPLAY_XFAILED 64 /* X failed */
+#define DISPLAY_GREETERFAILED 65 /* greeter failed (crashed) */
+#define DISPLAY_RESTARTGREETER 127 /* Restart greeter */
+#define DISPLAY_RESTARTGDM 128 /* Restart GDM */
+
+enum {
+ DISPLAY_UNBORN /* Not yet started */,
+ DISPLAY_ALIVE /* Yay! we're alive (non-XDMCP) */,
+ XDMCP_PENDING /* Pending XDMCP display */,
+ XDMCP_MANAGED /* Managed XDMCP display */,
+ DISPLAY_DEAD /* Left for dead */,
+ DISPLAY_CONFIG /* in process of being configured */
+};
+
#define TYPE_STATIC 1 /* X server defined in GDM configuration */
#define TYPE_XDMCP 2 /* Remote display/Xserver */
#define TYPE_FLEXI 3 /* Local Flexi X server */
@@ -177,6 +203,7 @@ struct _GdmDisplay
/* order in the Xservers file for sessreg, -1 if unset yet */
int x_servers_order;
+ gboolean wait_for_go;
/* STATIC TYPE */
diff --git a/daemon/filecheck.c b/daemon/filecheck.c
index 027a5321..8c43d193 100644
--- a/daemon/filecheck.c
+++ b/daemon/filecheck.c
@@ -25,7 +25,6 @@
#include "gdm.h"
#include "gdm-common.h"
-#include "gdm-daemon-config.h"
#include "filecheck.h"
@@ -63,18 +62,8 @@ gdm_file_check (const gchar *caller,
ve_string_empty (file))
return FALSE;
- /* Stat on automounted directory - append the '/.' to dereference mount point.
- Do this only if GdmSupportAutomount is true (default is false)
- 2006-09-22, Jerzy Borkowski, CAMK */
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_SUPPORT_AUTOMOUNT)) {
- dirautofs = g_strconcat(dir, "/.", NULL);
- VE_IGNORE_EINTR (r = stat (dirautofs, &statbuf));
- g_free(dirautofs);
- }
- /* Stat directory */
- else {
- VE_IGNORE_EINTR (r = stat (dir, &statbuf));
- }
+
+ VE_IGNORE_EINTR (r = stat (dir, &statbuf));
if (r < 0) {
if ( ! absentdirok)
@@ -83,17 +72,6 @@ gdm_file_check (const gchar *caller,
return FALSE;
}
- /* Check if dir is owned by the user ...
- Only, if GDM_KEY_CHECK_DIR_OWNER is true (default)
- This is a "hack" for directories not owned by
- the user.
- 2004-06-22, Andreas Schubert, MATHEMA Software GmbH */
-
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_CHECK_DIR_OWNER) && (statbuf.st_uid != user)) {
- g_warning (_("%s: %s is not owned by uid %d."), caller, dir, user);
- return FALSE;
- }
-
/* ... if group has write permission ... */
if G_UNLIKELY (perms < 1 && (statbuf.st_mode & S_IWGRP) == S_IWGRP) {
g_warning (_("%s: %s is writable by group."), caller, dir);
@@ -209,14 +187,6 @@ gdm_auth_file_check (const gchar *caller,
return FALSE;
}
- usermaxfile = gdm_daemon_config_get_value_int (GDM_KEY_USER_MAX_FILE);
- /* ... and smaller than sysadmin specified limit. */
- if G_UNLIKELY (usermaxfile && statbuf.st_size > usermaxfile) {
- g_warning (_("%s: %s is bigger than sysadmin specified maximum file size."),
- caller, authfile);
- return FALSE;
- }
-
/* Yeap, this file is ok */
return TRUE;
}
diff --git a/daemon/gdm-daemon-config-entries.h b/daemon/gdm-daemon-config-entries.h
index f335ed17..343bbf3d 100644
--- a/daemon/gdm-daemon-config-entries.h
+++ b/daemon/gdm-daemon-config-entries.h
@@ -73,7 +73,6 @@ typedef enum {
GDM_ID_CUSTOM_CMD_NO_RESTART_TEMPLATE,
GDM_ID_CUSTOM_CMD_IS_PERSISTENT_TEMPLATE,
GDM_ID_ROOT_PATH,
- GDM_ID_SERV_AUTHDIR,
GDM_ID_SESSION_DESKTOP_DIR,
GDM_ID_BASE_XSESSION,
GDM_ID_DEFAULT_SESSION,
@@ -313,7 +312,6 @@ static const GdmConfigEntry gdm_daemon_config_entries [] = {
{ GDM_CONFIG_GROUP_DAEMON, "FailsafeXServer", GDM_CONFIG_VALUE_STRING, NULL, GDM_ID_FAILSAFE_XSERVER },
{ GDM_CONFIG_GROUP_DAEMON, "XKeepsCrashing", GDM_CONFIG_VALUE_STRING, GDMCONFDIR "/XKeepsCrashing", GDM_ID_X_KEEPS_CRASHING },
{ GDM_CONFIG_GROUP_DAEMON, "RootPath", GDM_CONFIG_VALUE_STRING, "/sbin:/usr/sbin:" GDM_USER_PATH, GDM_ID_ROOT_PATH },
- { GDM_CONFIG_GROUP_DAEMON, "ServAuthDir", GDM_CONFIG_VALUE_STRING, AUTHDIR, GDM_ID_SERV_AUTHDIR },
{ GDM_CONFIG_GROUP_DAEMON, "SessionDesktopDir", GDM_CONFIG_VALUE_STRING, "/etc/X11/sessions/:" DMCONFDIR "/Sessions/:" DATADIR "/gdm/BuiltInSessions/:" DATADIR "/xsessions/", GDM_ID_SESSION_DESKTOP_DIR },
{ GDM_CONFIG_GROUP_DAEMON, "BaseXsession", GDM_CONFIG_VALUE_STRING, GDMCONFDIR "/Xsession", GDM_ID_BASE_XSESSION },
{ GDM_CONFIG_GROUP_DAEMON, "DefaultSession", GDM_CONFIG_VALUE_STRING, "gnome.desktop", GDM_ID_DEFAULT_SESSION },
diff --git a/daemon/gdm-daemon-config.c b/daemon/gdm-daemon-config.c
index 36a02851..323b8fd8 100644
--- a/daemon/gdm-daemon-config.c
+++ b/daemon/gdm-daemon-config.c
@@ -2324,268 +2324,6 @@ gdm_daemon_config_signal_terminthup_was_notified (void)
}
}
-/**
- * check_user_file
- * check_global_file
- * is_in_trusted_pic_dir
- * get_facefile_from_gnome2_dir_config
- * path_is_local
- * gdm_daemon_config_get_facefile_from_home
- * gdm_daemon_config_get_facefile_from_global
- *
- * These functions are used for accessing the user's face image from their
- * home directory.
- */
-static gboolean
-check_user_file (const char *path,
- guint uid)
-{
- char *dir;
- char *file;
- gboolean is_ok;
-
- if (path == NULL)
- return FALSE;
-
- if (g_access (path, R_OK) != 0)
- return FALSE;
-
- dir = g_path_get_dirname (path);
- file = g_path_get_basename (path);
-
- is_ok = gdm_file_check ("run_pictures",
- uid,
- dir,
- file,
- TRUE, TRUE,
- gdm_daemon_config_get_value_int (GDM_KEY_USER_MAX_FILE),
- gdm_daemon_config_get_value_int (GDM_KEY_RELAX_PERM));
- g_free (dir);
- g_free (file);
-
- return is_ok;
-}
-
-static gboolean
-check_global_file (const char *path,
- guint uid)
-{
- if (path == NULL)
- return FALSE;
-
- if (g_access (path, R_OK) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-/* If path starts with a "trusted" directory, don't sanity check things */
-/* This is really somewhat "outdated" as we now really want things in
- * the picture dir or in ~/.gnome2/photo */
-static gboolean
-is_in_trusted_pic_dir (const char *path)
-{
- /* our own pixmap dir is trusted */
- if (strncmp (path, PIXMAPDIR, sizeof (PIXMAPDIR)) == 0)
- return TRUE;
-
- return FALSE;
-}
-
-static gchar *
-get_facefile_from_gnome2_dir_config (const char *homedir,
- guint uid)
-{
- char *picfile = NULL;
- char *cfgdir;
-
- /* Sanity check on ~user/.gnome2/gdm */
- cfgdir = g_build_filename (homedir, ".gnome2", "gdm", NULL);
- if (G_LIKELY (check_user_file (cfgdir, uid))) {
- GKeyFile *cfg;
- char *cfgfile;
-
- cfgfile = g_build_filename (homedir, ".gnome2", "gdm", NULL);
- cfg = gdm_common_config_load (cfgfile, NULL);
- g_free (cfgfile);
-
- if (cfg != NULL) {
- gdm_common_config_get_string (cfg, "face/picture=", &picfile, NULL);
- g_key_file_free (cfg);
- }
-
- /* must exist and be absolute (note that this check
- * catches empty strings)*/
- /* Note that these days we just set ~/.face */
- if G_UNLIKELY (picfile != NULL &&
- (picfile[0] != '/' ||
- /* this catches readability by user */
- g_access (picfile, R_OK) != 0)) {
- g_free (picfile);
- picfile = NULL;
- }
-
- if (picfile != NULL) {
- char buf[PATH_MAX];
- if (realpath (picfile, buf) == NULL) {
- g_free (picfile);
- picfile = NULL;
- } else {
- g_free (picfile);
- picfile = g_strdup (buf);
- }
- }
-
- if G_UNLIKELY (picfile != NULL) {
- if (! is_in_trusted_pic_dir (picfile)) {
- /* if not in trusted dir, check it out */
-
- /* Note that strict permissions checking is done
- * on this file. Even if it may not even be owned by the
- * user. This setting should ONLY point to pics in trusted
- * dirs. */
- if (! check_user_file (picfile, uid)) {
- g_free (picfile);
- picfile = NULL;
- }
- }
- }
- }
- g_free (cfgdir);
-
- return picfile;
-}
-
-static GHashTable *fstype_hash = NULL;
-extern char *filesystem_type (char *path, char *relpath, struct stat *statp);
-
-static gboolean
-path_is_local (const char *path)
-{
- gpointer local = NULL;
-
- if (path == NULL)
- return FALSE;
-
- if (fstype_hash == NULL)
- fstype_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- else
- local = g_hash_table_lookup (fstype_hash, path);
-
- if (local == NULL) {
- struct stat statbuf;
-
- if (g_stat (path, &statbuf) == 0) {
- char *type = filesystem_type ((char *)path, (char *)path, &statbuf);
- gboolean is_local = ((strcmp (ve_sure_string (type), "nfs") != 0) &&
- (strcmp (ve_sure_string (type), "afs") != 0) &&
- (strcmp (ve_sure_string (type), "autofs") != 0) &&
- (strcmp (ve_sure_string (type), "unknown") != 0) &&
- (strcmp (ve_sure_string (type), "ncpfs") != 0));
- local = GINT_TO_POINTER (is_local ? 1 : -1);
- g_hash_table_insert (fstype_hash, g_strdup (path), local);
- }
- }
-
- return GPOINTER_TO_INT (local) > 0;
-}
-
-gchar *
-gdm_daemon_config_get_facefile_from_home (const char *homedir,
- guint uid)
-{
- char *picfile = NULL;
- char *path;
- gboolean is_local;
-
- /* special case: look at parent of home to detect autofs
- this is so we don't try to trigger an automount */
- path = g_path_get_dirname (homedir);
- is_local = path_is_local (path);
- g_free (path);
-
- /* now check that home dir itself is local */
- if (is_local) {
- is_local = path_is_local (homedir);
- }
-
- /* Only look at local home directories so we don't try to
- read from remote (e.g. NFS) volumes */
- if (! is_local)
- return NULL;
-
- picfile = g_build_filename (homedir, ".face", NULL);
-
- if (check_user_file (picfile, uid))
- return picfile;
- else {
- g_free (picfile);
- picfile = NULL;
- }
-
- picfile = g_build_filename (homedir, ".face.icon", NULL);
-
- if (check_user_file (picfile, uid))
- return picfile;
- else {
- g_free (picfile);
- picfile = NULL;
- }
-
- picfile = get_facefile_from_gnome2_dir_config (homedir, uid);
- if (check_user_file (picfile, uid))
- return picfile;
- else {
- g_free (picfile);
- picfile = NULL;
- }
-
- /* Nothing found yet, try the old locations */
-
- picfile = g_build_filename (homedir, ".gnome2", "photo", NULL);
- if (check_user_file (picfile, uid))
- return picfile;
- else {
- g_free (picfile);
- picfile = NULL;
- }
-
- picfile = g_build_filename (homedir, ".gnome", "photo", NULL);
- if (check_user_file (picfile, uid))
- return picfile;
- else {
- g_free (picfile);
- picfile = NULL;
- }
-
- return NULL;
-}
-
-gchar *
-gdm_daemon_config_get_facefile_from_global (const char *username,
- guint uid)
-{
- char *picfile = NULL;
- const char *facedir;
-
- facedir = gdm_daemon_config_get_value_string (GDM_KEY_GLOBAL_FACE_DIR);
-
- /* Try the global face directory */
-
- picfile = g_build_filename (facedir, username, NULL);
-
- if (check_global_file (picfile, uid))
- return picfile;
-
- g_free (picfile);
- picfile = gdm_make_filename (facedir, username, ".png");
-
- if (check_global_file (picfile, uid))
- return picfile;
-
- g_free (picfile);
- return NULL;
-}
static gboolean
is_prog_in_path (const char *prog)
diff --git a/daemon/gdm-daemon-config.h b/daemon/gdm-daemon-config.h
index 7c4f3767..d15d6f10 100644
--- a/daemon/gdm-daemon-config.h
+++ b/daemon/gdm-daemon-config.h
@@ -22,7 +22,6 @@
#ifndef _GDM_DAEMON_CONFIG_H
#define _GDM_DAEMON_CONFIG_H
-#include "server.h"
#include "gdm-daemon-config-entries.h"
G_BEGIN_DECLS
diff --git a/daemon/gdm-display-store.c b/daemon/gdm-display-store.c
new file mode 100644
index 00000000..f6b469f7
--- /dev/null
+++ b/daemon/gdm-display-store.c
@@ -0,0 +1,219 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-display-store.h"
+#include "gdm-display.h"
+
+#define GDM_DISPLAY_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY_STORE, GdmDisplayStorePrivate))
+
+struct GdmDisplayStorePrivate
+{
+ GHashTable *displays;
+};
+
+enum {
+ DISPLAY_ADDED,
+ DISPLAY_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_display_store_class_init (GdmDisplayStoreClass *klass);
+static void gdm_display_store_init (GdmDisplayStore *display_store);
+static void gdm_display_store_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmDisplayStore, gdm_display_store, G_TYPE_OBJECT)
+
+GQuark
+gdm_display_store_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gdm_display_store_error");
+ }
+
+ return ret;
+}
+
+void
+gdm_display_store_clear (GdmDisplayStore *store)
+{
+ g_hash_table_remove_all (store->priv->displays);
+}
+
+gboolean
+gdm_display_store_remove (GdmDisplayStore *store,
+ GdmDisplay *display)
+{
+ g_warning ("Implement me");
+ return FALSE;
+}
+
+void
+gdm_display_store_foreach (GdmDisplayStore *store,
+ GdmDisplayStoreFunc func,
+ gpointer user_data)
+{
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (func != NULL);
+
+ g_hash_table_find (store->priv->displays,
+ (GHRFunc)func,
+ user_data);
+}
+
+GdmDisplay *
+gdm_display_store_find (GdmDisplayStore *store,
+ GdmDisplayStoreFunc predicate,
+ gpointer user_data)
+{
+ GdmDisplay *display;
+
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (predicate != NULL, NULL);
+
+ display = g_hash_table_find (store->priv->displays,
+ (GHRFunc)predicate,
+ user_data);
+ return display;
+}
+
+guint
+gdm_display_store_foreach_remove (GdmDisplayStore *store,
+ GdmDisplayStoreFunc func,
+ gpointer user_data)
+{
+ guint ret;
+
+ g_return_val_if_fail (store != NULL, 0);
+ g_return_val_if_fail (func != NULL, 0);
+
+ ret = g_hash_table_foreach_remove (store->priv->displays,
+ (GHRFunc)func,
+ user_data);
+
+ return ret;
+}
+
+void
+gdm_display_store_add (GdmDisplayStore *store,
+ GdmDisplay *display)
+{
+ char *id;
+
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (display != NULL);
+
+ gdm_display_get_id (display, &id, NULL);
+
+ g_debug ("Adding display %s to store", id);
+
+ g_hash_table_insert (store->priv->displays,
+ id,
+ g_object_ref (display));
+}
+
+static void
+gdm_display_store_class_init (GdmDisplayStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_display_store_finalize;
+
+ signals [DISPLAY_ADDED] =
+ g_signal_new ("display-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmDisplayStoreClass, display_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+ signals [DISPLAY_REMOVED] =
+ g_signal_new ("display-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmDisplayStoreClass, display_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
+ g_type_class_add_private (klass, sizeof (GdmDisplayStorePrivate));
+}
+
+static void
+display_unref (GdmDisplay *display)
+{
+ /* nothing yet */
+}
+
+static void
+gdm_display_store_init (GdmDisplayStore *store)
+{
+
+ store->priv = GDM_DISPLAY_STORE_GET_PRIVATE (store);
+
+ store->priv->displays = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) display_unref);
+}
+
+static void
+gdm_display_store_finalize (GObject *object)
+{
+ GdmDisplayStore *display_store;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_DISPLAY_STORE (object));
+
+ display_store = GDM_DISPLAY_STORE (object);
+
+ g_return_if_fail (display_store->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_display_store_parent_class)->finalize (object);
+}
+
+GdmDisplayStore *
+gdm_display_store_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_DISPLAY_STORE,
+ NULL);
+
+ return GDM_DISPLAY_STORE (object);
+}
diff --git a/daemon/gdm-display-store.h b/daemon/gdm-display-store.h
new file mode 100644
index 00000000..1c7f78bc
--- /dev/null
+++ b/daemon/gdm-display-store.h
@@ -0,0 +1,89 @@
+/* -*- 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_DISPLAY_STORE_H
+#define __GDM_DISPLAY_STORE_H
+
+#include <glib-object.h>
+#include "gdm-display.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_DISPLAY_STORE (gdm_display_store_get_type ())
+#define GDM_DISPLAY_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DISPLAY_STORE, GdmDisplayStore))
+#define GDM_DISPLAY_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DISPLAY_STORE, GdmDisplayStoreClass))
+#define GDM_IS_DISPLAY_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DISPLAY_STORE))
+#define GDM_IS_DISPLAY_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DISPLAY_STORE))
+#define GDM_DISPLAY_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DISPLAY_STORE, GdmDisplayStoreClass))
+
+typedef struct GdmDisplayStorePrivate GdmDisplayStorePrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmDisplayStorePrivate *priv;
+} GdmDisplayStore;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* display_added) (GdmDisplayStore *display_store,
+ GdmDisplay *display);
+ void (* display_removed) (GdmDisplayStore *display_store,
+ GdmDisplay *display);
+} GdmDisplayStoreClass;
+
+typedef enum
+{
+ GDM_DISPLAY_STORE_ERROR_GENERAL
+} GdmDisplayStoreError;
+
+#define GDM_DISPLAY_STORE_ERROR gdm_display_store_error_quark ()
+
+typedef gboolean (*GdmDisplayStoreFunc) (const char *id,
+ GdmDisplay *display,
+ gpointer user_data);
+
+GQuark gdm_display_store_error_quark (void);
+GType gdm_display_store_get_type (void);
+
+GdmDisplayStore * gdm_display_store_new (void);
+
+void gdm_display_store_add (GdmDisplayStore *store,
+ GdmDisplay *display);
+void gdm_display_store_clear (GdmDisplayStore *store);
+gboolean gdm_display_store_remove (GdmDisplayStore *store,
+ GdmDisplay *display);
+void gdm_display_store_foreach (GdmDisplayStore *store,
+ GdmDisplayStoreFunc func,
+ gpointer user_data);
+guint gdm_display_store_foreach_remove (GdmDisplayStore *store,
+ GdmDisplayStoreFunc func,
+ gpointer user_data);
+GdmDisplay * gdm_display_store_find (GdmDisplayStore *store,
+ GdmDisplayStoreFunc predicate,
+ gpointer user_data);
+
+
+G_END_DECLS
+
+#endif /* __GDM_DISPLAY_STORE_H */
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
new file mode 100644
index 00000000..f48cc232
--- /dev/null
+++ b/daemon/gdm-display.c
@@ -0,0 +1,546 @@
+/* -*- 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 <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-display.h"
+#include "gdm-display-glue.h"
+
+#include "gdm-slave-proxy.h"
+
+#include "auth.h"
+
+static guint32 display_serial = 1;
+
+#define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate))
+
+struct GdmDisplayPrivate
+{
+ char *id;
+ char *name;
+ int number;
+ int status;
+ time_t creation_time;
+ char *cookie;
+ char *binary_cookie;
+ char *authority_file;
+
+ gboolean is_local;
+
+ GdmSlaveProxy *slave_proxy;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_NAME,
+ PROP_NUMBER,
+ PROP_COOKIE,
+ PROP_BINARY_COOKIE,
+ PROP_AUTHORITY_FILE,
+ PROP_IS_LOCAL,
+};
+
+static void gdm_display_class_init (GdmDisplayClass *klass);
+static void gdm_display_init (GdmDisplay *display);
+static void gdm_display_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (GdmDisplay, gdm_display, G_TYPE_OBJECT)
+
+GQuark
+gdm_display_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gdm_display_error");
+ }
+
+ return ret;
+}
+
+static guint32
+get_next_display_serial (void)
+{
+ guint32 serial;
+
+ serial = display_serial++;
+
+ if ((gint32)display_serial < 0) {
+ display_serial = 1;
+ }
+
+ return serial;
+}
+
+char *
+gdm_display_get_binary_cookie (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), NULL);
+
+ return g_strdup (display->priv->binary_cookie);
+}
+
+time_t
+gdm_display_get_creation_time (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), 0);
+
+ return display->priv->creation_time;
+}
+
+int
+gdm_display_get_status (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), 0);
+
+ return display->priv->status;
+}
+
+static gboolean
+gdm_display_real_create_authority (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_create_authority (GdmDisplay *display)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ g_object_ref (display);
+ ret = GDM_DISPLAY_GET_CLASS (display)->create_authority (display);
+ g_object_unref (display);
+
+ return ret;
+}
+
+static gboolean
+gdm_display_real_manage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ g_debug ("Manage display");
+
+ display->priv->status = GDM_DISPLAY_MANAGED;
+
+ g_assert (display->priv->slave_proxy == NULL);
+
+ display->priv->slave_proxy = gdm_slave_proxy_new (display->priv->id);
+ gdm_slave_proxy_start (display->priv->slave_proxy);
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_manage (GdmDisplay *display)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ g_object_ref (display);
+ ret = GDM_DISPLAY_GET_CLASS (display)->manage (display);
+ g_object_unref (display);
+
+ return ret;
+}
+
+static gboolean
+gdm_display_real_unmanage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ display->priv->status = GDM_DISPLAY_UNMANAGED;
+
+ if (display->priv->slave_proxy != NULL) {
+ gdm_slave_proxy_stop (display->priv->slave_proxy);
+
+ g_object_unref (display->priv->slave_proxy);
+ display->priv->slave_proxy = NULL;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_unmanage (GdmDisplay *display)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ g_object_ref (display);
+ ret = GDM_DISPLAY_GET_CLASS (display)->unmanage (display);
+ g_object_unref (display);
+
+ return ret;
+}
+
+gboolean
+gdm_display_get_id (GdmDisplay *display,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ if (id != NULL) {
+ *id = g_strdup (display->priv->id);
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_get_name (GdmDisplay *display,
+ char **name,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ if (name != NULL) {
+ *name = g_strdup (display->priv->name);
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_get_number (GdmDisplay *display,
+ int *number,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ if (number != NULL) {
+ *number = display->priv->number;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_display_is_local (GdmDisplay *display,
+ gboolean *local,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ if (local != NULL) {
+ *local = display->priv->is_local;
+ }
+
+ return TRUE;
+}
+
+static void
+_gdm_display_set_id (GdmDisplay *display,
+ const char *id)
+{
+ g_free (display->priv->id);
+ display->priv->id = g_strdup (id);
+}
+
+static void
+_gdm_display_set_name (GdmDisplay *display,
+ const char *name)
+{
+ g_free (display->priv->name);
+ display->priv->name = g_strdup (name);
+}
+
+static void
+_gdm_display_set_cookie (GdmDisplay *display,
+ const char *cookie)
+{
+ g_free (display->priv->cookie);
+ display->priv->cookie = g_strdup (cookie);
+}
+
+static void
+_gdm_display_set_binary_cookie (GdmDisplay *display,
+ const char *cookie)
+{
+ g_free (display->priv->binary_cookie);
+ display->priv->binary_cookie = g_strdup (cookie);
+}
+
+static void
+_gdm_display_set_authority_file (GdmDisplay *display,
+ const char *file)
+{
+ g_free (display->priv->authority_file);
+ display->priv->authority_file = g_strdup (file);
+}
+
+static void
+_gdm_display_set_number (GdmDisplay *display,
+ int num)
+{
+ display->priv->number = num;
+}
+
+static void
+_gdm_display_set_is_local (GdmDisplay *display,
+ gboolean is_local)
+{
+ display->priv->is_local = is_local;
+}
+
+static void
+gdm_display_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmDisplay *self;
+
+ self = GDM_DISPLAY (object);
+
+ switch (prop_id) {
+ case PROP_ID:
+ _gdm_display_set_id (self, g_value_get_string (value));
+ break;
+ case PROP_NAME:
+ _gdm_display_set_name (self, g_value_get_string (value));
+ break;
+ case PROP_COOKIE:
+ _gdm_display_set_cookie (self, g_value_get_string (value));
+ break;
+ case PROP_BINARY_COOKIE:
+ _gdm_display_set_binary_cookie (self, g_value_get_string (value));
+ break;
+ case PROP_AUTHORITY_FILE:
+ _gdm_display_set_authority_file (self, g_value_get_string (value));
+ break;
+ case PROP_NUMBER:
+ _gdm_display_set_number (self, g_value_get_int (value));
+ break;
+ case PROP_IS_LOCAL:
+ _gdm_display_set_is_local (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_display_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmDisplay *self;
+
+ self = GDM_DISPLAY (object);
+
+ switch (prop_id) {
+ case PROP_ID:
+ g_value_set_string (value, self->priv->id);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, self->priv->name);
+ break;
+ case PROP_COOKIE:
+ g_value_set_string (value, self->priv->cookie);
+ break;
+ case PROP_BINARY_COOKIE:
+ g_value_set_string (value, self->priv->binary_cookie);
+ break;
+ case PROP_AUTHORITY_FILE:
+ g_value_set_string (value, self->priv->authority_file);
+ break;
+ case PROP_NUMBER:
+ g_value_set_int (value, self->priv->number);
+ break;
+ case PROP_IS_LOCAL:
+ g_value_set_boolean (value, self->priv->is_local);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+register_display (GdmDisplay *display)
+{
+ GError *error = NULL;
+
+ error = NULL;
+ display->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (display->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+
+ dbus_g_connection_register_g_object (display->priv->connection, display->priv->id, G_OBJECT (display));
+
+ return TRUE;
+}
+
+/*
+ dbus-send --system --print-reply --dest=org.gnome.DisplayManager /org/gnome/DisplayManager/Display1 org.freedesktop.DBus.Introspectable.Introspect
+*/
+
+static GObject *
+gdm_display_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmDisplay *display;
+ GdmDisplayClass *klass;
+ gboolean res;
+
+ klass = GDM_DISPLAY_CLASS (g_type_class_peek (GDM_TYPE_DISPLAY));
+
+ display = GDM_DISPLAY (G_OBJECT_CLASS (gdm_display_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ display->priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Display%u", get_next_display_serial ());
+
+ res = register_display (display);
+ if (! res) {
+ g_warning ("Unable to register display with system bus");
+ }
+
+ return G_OBJECT (display);
+}
+
+static void
+gdm_display_class_init (GdmDisplayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_display_get_property;
+ object_class->set_property = gdm_display_set_property;
+ object_class->constructor = gdm_display_constructor;
+ object_class->finalize = gdm_display_finalize;
+
+ klass->create_authority = gdm_display_real_create_authority;
+ klass->manage = gdm_display_real_manage;
+ klass->unmanage = gdm_display_real_unmanage;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "id",
+ "id",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_COOKIE,
+ g_param_spec_string ("cookie",
+ "cookie",
+ "cookie",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_BINARY_COOKIE,
+ g_param_spec_string ("binary-cookie",
+ "binary-cookie",
+ "binary-cookie",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_AUTHORITY_FILE,
+ g_param_spec_string ("authority-file",
+ "authority file",
+ "authority file",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_NUMBER,
+ g_param_spec_int ("number",
+ "number",
+ "number",
+ -1,
+ G_MAXINT,
+ -1,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_IS_LOCAL,
+ g_param_spec_boolean ("is-local",
+ NULL,
+ NULL,
+ TRUE,
+ 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);
+}
+
+static void
+gdm_display_init (GdmDisplay *display)
+{
+
+ display->priv = GDM_DISPLAY_GET_PRIVATE (display);
+
+ display->priv->status = GDM_DISPLAY_UNMANAGED;
+ display->priv->creation_time = time (NULL);
+}
+
+static void
+gdm_display_finalize (GObject *object)
+{
+ GdmDisplay *display;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_DISPLAY (object));
+
+ display = GDM_DISPLAY (object);
+
+ g_return_if_fail (display->priv != NULL);
+
+ g_free (display->priv->id);
+
+ G_OBJECT_CLASS (gdm_display_parent_class)->finalize (object);
+}
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
new file mode 100644
index 00000000..8dc7ae5e
--- /dev/null
+++ b/daemon/gdm-display.h
@@ -0,0 +1,98 @@
+/* -*- 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_DISPLAY_H
+#define __GDM_DISPLAY_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_DISPLAY (gdm_display_get_type ())
+#define GDM_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DISPLAY, GdmDisplay))
+#define GDM_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DISPLAY, GdmDisplayClass))
+#define GDM_IS_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DISPLAY))
+#define GDM_IS_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DISPLAY))
+#define GDM_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DISPLAY, GdmDisplayClass))
+
+typedef struct GdmDisplayPrivate GdmDisplayPrivate;
+
+typedef enum {
+ GDM_DISPLAY_UNMANAGED,
+ GDM_DISPLAY_MANAGED
+} GdmDisplayStatus;
+
+typedef struct
+{
+ GObject parent;
+ GdmDisplayPrivate *priv;
+} GdmDisplay;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ /* methods */
+ gboolean (*create_authority) (GdmDisplay *display);
+ gboolean (*manage) (GdmDisplay *display);
+ gboolean (*unmanage) (GdmDisplay *display);
+
+} GdmDisplayClass;
+
+typedef enum
+{
+ GDM_DISPLAY_ERROR_GENERAL
+} GdmDisplayError;
+
+#define GDM_DISPLAY_ERROR gdm_display_error_quark ()
+
+GQuark gdm_display_error_quark (void);
+GType gdm_display_get_type (void);
+
+int gdm_display_get_status (GdmDisplay *display);
+time_t gdm_display_get_creation_time (GdmDisplay *display);
+char * gdm_display_get_cookie (GdmDisplay *display);
+char * gdm_display_get_binary_cookie (GdmDisplay *display);
+char * gdm_display_get_user_auth (GdmDisplay *display);
+
+gboolean gdm_display_create_authority (GdmDisplay *display);
+gboolean gdm_display_manage (GdmDisplay *display);
+gboolean gdm_display_unmanage (GdmDisplay *display);
+
+
+/* exported to bus */
+gboolean gdm_display_get_id (GdmDisplay *display,
+ char **id,
+ GError **error);
+gboolean gdm_display_get_number (GdmDisplay *display,
+ int *number,
+ GError **error);
+gboolean gdm_display_get_name (GdmDisplay *display,
+ char **name,
+ GError **error);
+gboolean gdm_display_is_local (GdmDisplay *display,
+ gboolean *local,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GDM_DISPLAY_H */
diff --git a/daemon/gdm-display.xml b/daemon/gdm-display.xml
new file mode 100644
index 00000000..07a27e20
--- /dev/null
+++ b/daemon/gdm-display.xml
@@ -0,0 +1,17 @@
+<!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.Display">
+ <method name="GetId">
+ <arg name="id" direction="out" type="o"/>
+ </method>
+ <method name="GetName">
+ <arg name="name" direction="out" type="s"/>
+ </method>
+ <method name="GetNumber">
+ <arg name="number" direction="out" type="i"/>
+ </method>
+ <method name="IsLocal">
+ <arg name="local" direction="out" type="b"/>
+ </method>
+ </interface>
+</node>
diff --git a/daemon/gdm-greeter.c b/daemon/gdm-greeter.c
new file mode 100644
index 00000000..1c10e847
--- /dev/null
+++ b/daemon/gdm-greeter.c
@@ -0,0 +1,1147 @@
+/* -*- 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>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+#include "filecheck.h"
+
+#include "gdm-greeter.h"
+#include "gdm-socket-protocol.h"
+
+extern char **environ;
+
+#define GDM_GREETER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER, GdmGreeterPrivate))
+
+struct GdmGreeterPrivate
+{
+ char *command;
+ GPid pid;
+
+ char *username;
+ uid_t uid;
+ gid_t gid;
+ int pipe1[2];
+ int pipe2[2];
+
+ int greeter_fd_in;
+ int greeter_fd_out;
+
+ char *display_name;
+ char *display_auth_file;
+
+ int user_max_filesize;
+
+ gboolean interrupted;
+ gboolean always_restart_greeter;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_NAME,
+};
+
+static void gdm_greeter_class_init (GdmGreeterClass *klass);
+static void gdm_greeter_init (GdmGreeter *greeter);
+static void gdm_greeter_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmGreeter, gdm_greeter, G_TYPE_OBJECT)
+
+gboolean
+gdm_greeter_stop (GdmGreeter *greeter)
+{
+ g_debug ("Stopping greeter");
+
+ return TRUE;
+}
+
+static void
+change_user (GdmGreeter *greeter)
+{
+ if (greeter->priv->uid != 0) {
+ struct passwd *pwent;
+
+ pwent = getpwuid (greeter->priv->uid);
+ if (pwent == NULL) {
+ g_warning (_("%s: Greeter was to be spawned by uid %d but "
+ "that user doesn't exist"),
+ "gdm_greeter_spawn",
+ (int)greeter->priv->uid);
+ _exit (1);
+ }
+
+ if (setgid (greeter->priv->gid) < 0) {
+ g_warning (_("%s: Couldn't set groupid to %d"),
+ "gdm_greeter_spawn", (int)greeter->priv->gid);
+ _exit (1);
+ }
+
+ if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
+ g_warning (_("%s: initgroups () failed for %s"),
+ "gdm_greeter_spawn", pwent->pw_name);
+ _exit (1);
+ }
+
+ if (setuid (greeter->priv->uid) < 0) {
+ g_warning (_("%s: Couldn't set userid to %d"),
+ "gdm_greeter_spawn", (int)greeter->priv->uid);
+ _exit (1);
+ }
+ } else {
+ gid_t groups[1] = { 0 };
+
+ if (setgid (0) < 0) {
+ g_warning (_("%s: Couldn't set groupid to 0"),
+ "gdm_greeter_spawn");
+ /* Don't error out, it's not fatal, if it fails we'll
+ * just still be */
+ }
+ /* this will get rid of any suplementary groups etc... */
+ setgroups (1, groups);
+ }
+}
+
+static void
+greeter_child_setup (GdmGreeter *greeter)
+{
+
+ /* Plumbing */
+ VE_IGNORE_EINTR (close (greeter->priv->pipe1[1]));
+ VE_IGNORE_EINTR (close (greeter->priv->pipe2[0]));
+
+ VE_IGNORE_EINTR (dup2 (greeter->priv->pipe1[0], STDIN_FILENO));
+ VE_IGNORE_EINTR (dup2 (greeter->priv->pipe2[1], STDOUT_FILENO));
+
+ gdm_close_all_descriptors (2 /* from */,
+ -1 /* except */,
+ -1 /* except2 */);
+
+ gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
+
+ change_user (greeter);
+}
+
+static void
+listify_hash (const char *key,
+ const char *value,
+ GPtrArray *env)
+{
+ char *str;
+ str = g_strdup_printf ("%s=%s", key, value);
+ g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_greeter_environment (GdmGreeter *greeter)
+{
+ GPtrArray *env;
+ char **l;
+ GHashTable *hash;
+ struct passwd *pwent;
+
+ 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);
+ for (l = environ; *l != NULL; l++) {
+ char **str;
+ str = g_strsplit (*l, "=", 2);
+ g_hash_table_insert (hash, str[0], str[1]);
+ }
+
+
+ g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (greeter->priv->display_auth_file));
+ g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (greeter->priv->display_name));
+
+#if 0
+ /* hackish ain't it */
+ set_xnest_parent_stuff ();
+#endif
+
+ g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (greeter->priv->username));
+ g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (greeter->priv->username));
+ g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (greeter->priv->username));
+
+ g_hash_table_insert (hash, g_strdup ("GDM_GREETER_PROTOCOL_VERSION"), g_strdup (GDM_GREETER_PROTOCOL_VERSION));
+ g_hash_table_insert (hash, g_strdup ("GDM_VERSION"), g_strdup (VERSION));
+ g_hash_table_remove (hash, "MAIL");
+
+ 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"));
+
+ pwent = getpwnam (greeter->priv->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
+ defaultpath = gdm_daemon_config_get_value_string (GDM_KEY_PATH);
+ if (ve_string_empty (g_getenv ("PATH"))) {
+ g_setenv ("PATH", defaultpath, TRUE);
+ } else if ( ! ve_string_empty (defaultpath)) {
+ gchar *temp_string = g_strconcat (g_getenv ("PATH"),
+ ":", defaultpath, NULL);
+ g_setenv ("PATH", temp_string, TRUE);
+ g_free (temp_string);
+ }
+#endif
+
+ 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);
+ if (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG_GESTURES)) {
+ g_setenv ("G_DEBUG_GESTURES", "true", TRUE);
+ }
+#endif
+
+#if 0
+ if (SERVER_IS_FLEXI (d)) {
+ g_setenv ("GDM_FLEXI_SERVER", "yes", TRUE);
+ } else {
+ g_unsetenv ("GDM_FLEXI_SERVER");
+ }
+#endif
+
+
+ g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
+ g_hash_table_destroy (hash);
+
+ g_ptr_array_add (env, NULL);
+
+ return env;
+}
+
+static void
+gdm_slave_whack_temp_auth_file (GdmGreeter *greeter)
+{
+#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 (GdmGreeter *greeter)
+{
+#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
+whack_greeter_fds (GdmGreeter *greeter)
+{
+ if (greeter->priv->greeter_fd_out > 0)
+ VE_IGNORE_EINTR (close (greeter->priv->greeter_fd_out));
+ greeter->priv->greeter_fd_out = -1;
+ if (greeter->priv->greeter_fd_in > 0)
+ VE_IGNORE_EINTR (close (greeter->priv->greeter_fd_in));
+ greeter->priv->greeter_fd_in = -1;
+}
+
+/* return true for "there was an interruption received",
+ and interrupted will be TRUE if we are actually interrupted from doing what
+ we want. If FALSE is returned, just continue on as we would normally */
+static gboolean
+check_for_interruption (GdmGreeter *greeter,
+ const char *msg)
+{
+ /* Hell yeah we were interrupted, the greeter died */
+ if (msg == NULL) {
+ greeter->priv->interrupted = TRUE;
+ return TRUE;
+ }
+
+ if (msg[0] == BEL) {
+ /* Different interruptions come here */
+ /* Note that we don't want to actually do anything. We want
+ * to just set some flag and go on and schedule it after we
+ * dump out of the login in the main login checking loop */
+#if 0
+ switch (msg[1]) {
+ case GDM_INTERRUPT_TIMED_LOGIN:
+ /* only allow timed login if display is local,
+ * it is allowed for this display (it's only allowed
+ * for the first local display) and if it's set up
+ * correctly */
+ if ((d->attached || gdm_daemon_config_get_value_bool (GDM_KEY_ALLOW_REMOTE_AUTOLOGIN))
+ && d->timed_login_ok &&
+ ! ve_string_empty (ParsedTimedLogin) &&
+ strcmp (ParsedTimedLogin, gdm_root_user ()) != 0 &&
+ gdm_daemon_config_get_value_int (GDM_KEY_TIMED_LOGIN_DELAY) > 0) {
+ do_timed_login = TRUE;
+ }
+ break;
+ case GDM_INTERRUPT_CONFIGURE:
+ if (d->attached &&
+ gdm_daemon_config_get_value_bool_per_display (GDM_KEY_CONFIG_AVAILABLE, d->name) &&
+ gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, d->name) &&
+ ! ve_string_empty (gdm_daemon_config_get_value_string (GDM_KEY_CONFIGURATOR))) {
+ do_configurator = TRUE;
+ }
+ break;
+ case GDM_INTERRUPT_SUSPEND:
+ if (d->attached &&
+ gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, d->name) &&
+ ! ve_string_empty (gdm_daemon_config_get_value_string (GDM_KEY_SUSPEND))) {
+ gchar *msg = g_strdup_printf ("%s %ld",
+ GDM_SOP_SUSPEND_MACHINE,
+ (long)getpid ());
+
+ gdm_slave_send (msg, FALSE /* wait_for_ack */);
+ g_free (msg);
+ }
+ /* Not interrupted, continue reading input,
+ * just proxy this to the master server */
+ return TRUE;
+ case GDM_INTERRUPT_LOGIN_SOUND:
+ if (d->attached &&
+ ! play_login_sound (gdm_daemon_config_get_value_string (GDM_KEY_SOUND_ON_LOGIN_FILE))) {
+ gdm_error (_("Login sound requested on non-local display or the play software "
+ "cannot be run or the sound does not exist"));
+ }
+ return TRUE;
+ case GDM_INTERRUPT_SELECT_USER:
+ gdm_verify_select_user (&msg[2]);
+ break;
+ case GDM_INTERRUPT_CANCEL:
+ do_cancel = TRUE;
+ break;
+ case GDM_INTERRUPT_CUSTOM_CMD:
+ if (d->attached &&
+ ! ve_string_empty (&msg[2])) {
+ gchar *message = g_strdup_printf ("%s %ld %s",
+ GDM_SOP_CUSTOM_CMD,
+ (long)getpid (), &msg[2]);
+
+ gdm_slave_send (message, TRUE);
+ g_free (message);
+ }
+ return TRUE;
+ case GDM_INTERRUPT_THEME:
+ g_free (d->theme_name);
+ d->theme_name = NULL;
+ if ( ! ve_string_empty (&msg[2]))
+ d->theme_name = g_strdup (&msg[2]);
+ gdm_slave_send_string (GDM_SOP_CHOSEN_THEME, &msg[2]);
+ return TRUE;
+ case GDM_INTERRUPT_SELECT_LANG:
+ if (msg + 2) {
+ const char *locale;
+ const char *gdm_system_locale;
+
+ locale = (gchar*)(msg + 3);
+ gdm_system_locale = setlocale (LC_CTYPE, NULL);
+
+ greeter->priv->always_restart_greeter = (gboolean)(*(msg + 2));
+ ve_clearenv ();
+ if (!strcmp (locale, DEFAULT_LANGUAGE)) {
+ locale = gdm_system_locale;
+ }
+ g_setenv ("GDM_LANG", locale, TRUE);
+ g_setenv ("LANG", locale, TRUE);
+ g_unsetenv ("LC_ALL");
+ g_unsetenv ("LC_MESSAGES");
+ setlocale (LC_ALL, "");
+ setlocale (LC_MESSAGES, "");
+ gdm_saveenv ();
+
+ do_restart_greeter = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ /* this was an interruption, if it wasn't
+ * handled then the user will just get an error as if he
+ * entered an invalid login or passward. Seriously BEL
+ * cannot be part of a login/password really */
+ greeter->priv->interrupted = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static char *
+gdm_slave_greeter_ctl (GdmGreeter *greeter,
+ char cmd,
+ const char *str)
+{
+ char *buf = NULL;
+ int c;
+
+ if ( ! ve_string_empty (str)) {
+ gdm_fdprintf (greeter->priv->greeter_fd_out, "%c%c%s\n", STX, cmd, str);
+ } else {
+ gdm_fdprintf (greeter->priv->greeter_fd_out, "%c%c\n", STX, cmd);
+ }
+
+#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
+ /* let the other process (greeter) do its stuff */
+ sched_yield ();
+#endif
+
+ do {
+ g_free (buf);
+ buf = NULL;
+ /* Skip random junk that might have accumulated */
+ do {
+ c = gdm_fdgetc (greeter->priv->greeter_fd_in);
+ } while (c != EOF && c != STX);
+
+ if (c == EOF ||
+ (buf = gdm_fdgets (greeter->priv->greeter_fd_in)) == NULL) {
+ greeter->priv->interrupted = TRUE;
+ /* things don't seem well with the greeter, it probably died */
+ return NULL;
+ }
+ } while (check_for_interruption (greeter, buf) && ! greeter->priv->interrupted);
+
+ if ( ! ve_string_empty (buf)) {
+ return buf;
+ } else {
+ g_free (buf);
+ return NULL;
+ }
+}
+
+static void
+gdm_slave_greeter_ctl_no_ret (GdmGreeter *greeter,
+ char cmd,
+ const char *str)
+{
+ g_free (gdm_slave_greeter_ctl (greeter, cmd, str));
+}
+/**
+ * check_user_file
+ * check_global_file
+ * is_in_trusted_pic_dir
+ * get_facefile_from_gnome2_dir_config
+ * path_is_local
+ * gdm_daemon_config_get_facefile_from_home
+ * gdm_daemon_config_get_facefile_from_global
+ *
+ * These functions are used for accessing the user's face image from their
+ * home directory.
+ */
+static gboolean
+check_user_file (const char *path,
+ guint uid)
+{
+ char *dir;
+ char *file;
+ gboolean is_ok;
+
+ if (path == NULL)
+ return FALSE;
+
+ if (g_access (path, R_OK) != 0)
+ return FALSE;
+
+ dir = g_path_get_dirname (path);
+ file = g_path_get_basename (path);
+
+ is_ok = gdm_file_check ("run_pictures",
+ uid,
+ dir,
+ file,
+ TRUE, TRUE,
+ 0,
+ 0);
+ g_free (dir);
+ g_free (file);
+
+ return is_ok;
+}
+
+static gboolean
+check_global_file (const char *path,
+ guint uid)
+{
+ if (path == NULL)
+ return FALSE;
+
+ if (g_access (path, R_OK) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* If path starts with a "trusted" directory, don't sanity check things */
+/* This is really somewhat "outdated" as we now really want things in
+ * the picture dir or in ~/.gnome2/photo */
+static gboolean
+is_in_trusted_pic_dir (const char *path)
+{
+ /* our own pixmap dir is trusted */
+ if (strncmp (path, PIXMAPDIR, sizeof (PIXMAPDIR)) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gchar *
+get_facefile_from_gnome2_dir_config (const char *homedir,
+ guint uid)
+{
+ char *picfile = NULL;
+ char *cfgdir;
+
+ /* Sanity check on ~user/.gnome2/gdm */
+ cfgdir = g_build_filename (homedir, ".gnome2", "gdm", NULL);
+ if (G_LIKELY (check_user_file (cfgdir, uid))) {
+ GKeyFile *cfg;
+ char *cfgfile;
+
+ cfgfile = g_build_filename (homedir, ".gnome2", "gdm", NULL);
+ cfg = gdm_common_config_load (cfgfile, NULL);
+ g_free (cfgfile);
+
+ if (cfg != NULL) {
+ gdm_common_config_get_string (cfg, "face/picture=", &picfile, NULL);
+ g_key_file_free (cfg);
+ }
+
+ /* must exist and be absolute (note that this check
+ * catches empty strings)*/
+ /* Note that these days we just set ~/.face */
+ if G_UNLIKELY (picfile != NULL &&
+ (picfile[0] != '/' ||
+ /* this catches readability by user */
+ g_access (picfile, R_OK) != 0)) {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ if (picfile != NULL) {
+ char buf[PATH_MAX];
+ if (realpath (picfile, buf) == NULL) {
+ g_free (picfile);
+ picfile = NULL;
+ } else {
+ g_free (picfile);
+ picfile = g_strdup (buf);
+ }
+ }
+
+ if G_UNLIKELY (picfile != NULL) {
+ if (! is_in_trusted_pic_dir (picfile)) {
+ /* if not in trusted dir, check it out */
+
+ /* Note that strict permissions checking is done
+ * on this file. Even if it may not even be owned by the
+ * user. This setting should ONLY point to pics in trusted
+ * dirs. */
+ if (! check_user_file (picfile, uid)) {
+ g_free (picfile);
+ picfile = NULL;
+ }
+ }
+ }
+ }
+ g_free (cfgdir);
+
+ return picfile;
+}
+
+static GHashTable *fstype_hash = NULL;
+extern char *filesystem_type (char *path, char *relpath, struct stat *statp);
+
+static gboolean
+path_is_local (const char *path)
+{
+ gpointer local = NULL;
+
+ if (path == NULL)
+ return FALSE;
+
+ if (fstype_hash == NULL)
+ fstype_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ else
+ local = g_hash_table_lookup (fstype_hash, path);
+
+ if (local == NULL) {
+ struct stat statbuf;
+
+ if (g_stat (path, &statbuf) == 0) {
+ char *type = filesystem_type ((char *)path, (char *)path, &statbuf);
+ gboolean is_local = ((strcmp (ve_sure_string (type), "nfs") != 0) &&
+ (strcmp (ve_sure_string (type), "afs") != 0) &&
+ (strcmp (ve_sure_string (type), "autofs") != 0) &&
+ (strcmp (ve_sure_string (type), "unknown") != 0) &&
+ (strcmp (ve_sure_string (type), "ncpfs") != 0));
+ local = GINT_TO_POINTER (is_local ? 1 : -1);
+ g_hash_table_insert (fstype_hash, g_strdup (path), local);
+ }
+ }
+
+ return GPOINTER_TO_INT (local) > 0;
+}
+
+static char *
+gdm_daemon_config_get_facefile_from_home (const char *homedir,
+ guint uid)
+{
+ char *picfile = NULL;
+ char *path;
+ gboolean is_local;
+
+ /* special case: look at parent of home to detect autofs
+ this is so we don't try to trigger an automount */
+ path = g_path_get_dirname (homedir);
+ is_local = path_is_local (path);
+ g_free (path);
+
+ /* now check that home dir itself is local */
+ if (is_local) {
+ is_local = path_is_local (homedir);
+ }
+
+ /* Only look at local home directories so we don't try to
+ read from remote (e.g. NFS) volumes */
+ if (! is_local)
+ return NULL;
+
+ picfile = g_build_filename (homedir, ".face", NULL);
+
+ if (check_user_file (picfile, uid))
+ return picfile;
+ else {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ picfile = g_build_filename (homedir, ".face.icon", NULL);
+
+ if (check_user_file (picfile, uid))
+ return picfile;
+ else {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ picfile = get_facefile_from_gnome2_dir_config (homedir, uid);
+ if (check_user_file (picfile, uid))
+ return picfile;
+ else {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ /* Nothing found yet, try the old locations */
+
+ picfile = g_build_filename (homedir, ".gnome2", "photo", NULL);
+ if (check_user_file (picfile, uid))
+ return picfile;
+ else {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ picfile = g_build_filename (homedir, ".gnome", "photo", NULL);
+ if (check_user_file (picfile, uid))
+ return picfile;
+ else {
+ g_free (picfile);
+ picfile = NULL;
+ }
+
+ return NULL;
+}
+
+static char *
+gdm_daemon_config_get_facefile_from_global (const char *username,
+ guint uid)
+{
+#if 0
+ char *picfile = NULL;
+ const char *facedir;
+
+ facedir = gdm_daemon_config_get_value_string (GDM_KEY_GLOBAL_FACE_DIR);
+
+ /* Try the global face directory */
+
+ picfile = g_build_filename (facedir, username, NULL);
+
+ if (check_global_file (picfile, uid))
+ return picfile;
+
+ g_free (picfile);
+ picfile = gdm_make_filename (facedir, username, ".png");
+
+ if (check_global_file (picfile, uid))
+ return picfile;
+
+ g_free (picfile);
+#endif
+ return NULL;
+}
+
+static void
+gdm_slave_quick_exit (GdmGreeter *greeter)
+{
+ /* FIXME */
+ _exit (1);
+}
+
+/* This is VERY evil! */
+static void
+run_pictures (GdmGreeter *greeter)
+{
+ char *response;
+ int max_write;
+ char buf[1024];
+ size_t bytes;
+ struct passwd *pwent;
+ char *picfile;
+ FILE *fp;
+
+ response = NULL;
+ for (;;) {
+ struct stat s;
+ char *tmp, *ret;
+ int i, r;
+
+ g_free (response);
+ response = gdm_slave_greeter_ctl (greeter, GDM_NEEDPIC, "");
+ if (ve_string_empty (response)) {
+ g_free (response);
+ return;
+ }
+
+ pwent = getpwnam (response);
+ if G_UNLIKELY (pwent == NULL) {
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "");
+ continue;
+ }
+
+ picfile = NULL;
+
+ NEVER_FAILS_seteuid (0);
+ if G_UNLIKELY (setegid (pwent->pw_gid) != 0 ||
+ seteuid (pwent->pw_uid) != 0) {
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "");
+ continue;
+ }
+
+ picfile = gdm_daemon_config_get_facefile_from_home (pwent->pw_dir, pwent->pw_uid);
+
+ if (! picfile)
+ picfile = gdm_daemon_config_get_facefile_from_global (pwent->pw_name, pwent->pw_uid);
+
+ if (! picfile) {
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "");
+ continue;
+ }
+
+ VE_IGNORE_EINTR (r = g_stat (picfile, &s));
+ if G_UNLIKELY (r < 0 || s.st_size > greeter->priv->user_max_filesize) {
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "");
+ continue;
+ }
+
+ VE_IGNORE_EINTR (fp = fopen (picfile, "r"));
+ g_free (picfile);
+ if G_UNLIKELY (fp == NULL) {
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "");
+ continue;
+ }
+
+ tmp = g_strdup_printf ("buffer:%d", (int)s.st_size);
+ ret = gdm_slave_greeter_ctl (greeter, GDM_READPIC, tmp);
+ g_free (tmp);
+
+ if G_UNLIKELY (ret == NULL || strcmp (ret, "OK") != 0) {
+ VE_IGNORE_EINTR (fclose (fp));
+ g_free (ret);
+ continue;
+ }
+ g_free (ret);
+
+ gdm_fdprintf (greeter->priv->greeter_fd_out, "%c", STX);
+
+#ifdef PIPE_BUF
+ max_write = MIN (PIPE_BUF, sizeof (buf));
+#else
+ /* apparently Hurd doesn't have PIPE_BUF */
+ max_write = fpathconf (greeter->priv->greeter_fd_out, _PC_PIPE_BUF);
+ /* could return -1 if no limit */
+ if (max_write > 0)
+ max_write = MIN (max_write, sizeof (buf));
+ else
+ max_write = sizeof (buf);
+#endif
+
+ i = 0;
+ while (i < s.st_size) {
+ int written;
+
+ VE_IGNORE_EINTR (bytes = fread (buf, sizeof (char),
+ max_write, fp));
+
+ if (bytes <= 0)
+ break;
+
+ if G_UNLIKELY (i + bytes > s.st_size)
+ bytes = s.st_size - i;
+
+ /* write until we succeed in writing something */
+ VE_IGNORE_EINTR (written = write (greeter->priv->greeter_fd_out, buf, bytes));
+ if G_UNLIKELY (written < 0 &&
+ (errno == EPIPE || errno == EBADF)) {
+ /* something very, very bad has happened */
+
+ gdm_slave_quick_exit (greeter);
+ }
+
+ if G_UNLIKELY (written < 0)
+ written = 0;
+
+ /* write until we succeed in writing everything */
+ while (written < bytes) {
+ int n;
+ VE_IGNORE_EINTR (n = write (greeter->priv->greeter_fd_out, &buf[written], bytes-written));
+ if G_UNLIKELY (n < 0 &&
+ (errno == EPIPE || errno == EBADF)) {
+
+ /* something very, very bad has happened */
+ gdm_slave_quick_exit (greeter);
+
+ } else if G_LIKELY (n > 0) {
+ written += n;
+ }
+ }
+
+ /* we have written bytes bytes if it likes it or not */
+ i += bytes;
+ }
+
+ VE_IGNORE_EINTR (fclose (fp));
+
+ /* eek, this "could" happen, so just send some garbage */
+ while G_UNLIKELY (i < s.st_size) {
+ bytes = MIN (sizeof (buf), s.st_size - i);
+ errno = 0;
+ bytes = write (greeter->priv->greeter_fd_out, buf, bytes);
+ if G_UNLIKELY (bytes < 0 && (errno == EPIPE || errno == EBADF)) {
+
+ /* something very, very bad has happened */
+ gdm_slave_quick_exit (greeter);
+
+ }
+ if (bytes > 0)
+ i += bytes;
+ }
+
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_READPIC, "done");
+
+ }
+
+ g_free (response); /* not reached */
+}
+
+static gboolean
+gdm_greeter_spawn (GdmGreeter *greeter)
+{
+ gchar **argv;
+ GError *error;
+ GPtrArray *env;
+ gboolean ret;
+
+ ret = FALSE;
+
+ /* Open a pipe for greeter communications */
+ if (pipe (greeter->priv->pipe1) < 0) {
+ g_warning ("Can't init pipe to gdmgreeter");
+ exit (1);
+ }
+
+ if (pipe (greeter->priv->pipe2) < 0) {
+ VE_IGNORE_EINTR (close (greeter->priv->pipe1[0]));
+ VE_IGNORE_EINTR (close (greeter->priv->pipe1[1]));
+ g_warning ("Can't init pipe to gdmgreeter");
+ exit (1);
+ }
+
+ create_temp_auth_file (greeter);
+
+ g_debug ("Running greeter process: %s", greeter->priv->command);
+
+ argv = NULL;
+ if (! g_shell_parse_argv (greeter->priv->command, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ env = get_greeter_environment (greeter);
+
+ error = NULL;
+ ret = g_spawn_async_with_pipes (NULL,
+ argv,
+ (char **)env->pdata,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD,
+ (GSpawnChildSetupFunc)greeter_child_setup,
+ greeter,
+ &greeter->priv->pid,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+
+ if (! ret) {
+ g_warning ("Could not start command '%s': %s",
+ greeter->priv->command,
+ error->message);
+ g_error_free (error);
+ } else {
+
+ whack_greeter_fds (greeter);
+
+ greeter->priv->greeter_fd_out = greeter->priv->pipe1[1];
+ greeter->priv->greeter_fd_in = greeter->priv->pipe2[0];
+
+ g_debug ("gdm_slave_greeter: Greeter on pid %d", (int)greeter->priv->pid);
+ }
+
+
+ g_strfreev (argv);
+ out:
+
+ return ret;
+}
+
+/**
+ * gdm_greeter_start:
+ * @disp: Pointer to a GdmDisplay structure
+ *
+ * Starts a local X greeter. Handles retries and fatal errors properly.
+ */
+
+gboolean
+gdm_greeter_start (GdmGreeter *greeter)
+{
+ gboolean res;
+ const char *gdmlang;
+
+ res = gdm_greeter_spawn (greeter);
+
+ if (res) {
+ run_pictures (greeter); /* Append pictures to greeter if browsing is on */
+
+ if (greeter->priv->always_restart_greeter)
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_ALWAYS_RESTART, "Y");
+ else
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_ALWAYS_RESTART, "N");
+
+ gdmlang = g_getenv ("GDM_LANG");
+ if (gdmlang)
+ gdm_slave_greeter_ctl_no_ret (greeter, GDM_SETLANG, gdmlang);
+ }
+
+
+ return res;
+}
+
+static void
+_gdm_greeter_set_display_name (GdmGreeter *greeter,
+ const char *name)
+{
+ g_free (greeter->priv->display_name);
+ greeter->priv->display_name = g_strdup (name);
+}
+
+static void
+gdm_greeter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeter *self;
+
+ self = GDM_GREETER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_NAME:
+ _gdm_greeter_set_display_name (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeter *self;
+
+ self = GDM_GREETER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, self->priv->display_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_greeter_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmGreeter *greeter;
+ GdmGreeterClass *klass;
+ struct passwd *pwent;
+
+ klass = GDM_GREETER_CLASS (g_type_class_peek (GDM_TYPE_GREETER));
+
+ greeter = GDM_GREETER (G_OBJECT_CLASS (gdm_greeter_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ pwent = getpwuid (greeter->priv->uid);
+ if (pwent != NULL) {
+ greeter->priv->username = g_strdup (pwent->pw_name);
+ }
+
+ return G_OBJECT (greeter);
+}
+
+static void
+gdm_greeter_class_init (GdmGreeterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_greeter_get_property;
+ object_class->set_property = gdm_greeter_set_property;
+ object_class->constructor = gdm_greeter_constructor;
+ object_class->finalize = gdm_greeter_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmGreeterPrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "name",
+ "name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdm_greeter_init (GdmGreeter *greeter)
+{
+
+ greeter->priv = GDM_GREETER_GET_PRIVATE (greeter);
+
+ greeter->priv->pid = -1;
+
+ greeter->priv->command = g_strdup (LIBEXECDIR "/gdmgreeter");
+ greeter->priv->user_max_filesize = 65536;
+}
+
+static void
+gdm_greeter_finalize (GObject *object)
+{
+ GdmGreeter *greeter;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_GREETER (object));
+
+ greeter = GDM_GREETER (object);
+
+ g_return_if_fail (greeter->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_greeter_parent_class)->finalize (object);
+}
+
+GdmGreeter *
+gdm_greeter_new (const char *display_name)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_GREETER,
+ "display-name", display_name,
+ NULL);
+
+ return GDM_GREETER (object);
+}
diff --git a/daemon/gdm-greeter.h b/daemon/gdm-greeter.h
new file mode 100644
index 00000000..8a000342
--- /dev/null
+++ b/daemon/gdm-greeter.h
@@ -0,0 +1,57 @@
+/* -*- 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_H
+#define __GDM_GREETER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER (gdm_greeter_get_type ())
+#define GDM_GREETER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_GREETER, GdmGreeter))
+#define GDM_GREETER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_GREETER, GdmGreeterClass))
+#define GDM_IS_GREETER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_GREETER))
+#define GDM_IS_GREETER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_GREETER))
+#define GDM_GREETER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_GREETER, GdmGreeterClass))
+
+typedef struct GdmGreeterPrivate GdmGreeterPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmGreeterPrivate *priv;
+} GdmGreeter;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+} GdmGreeterClass;
+
+GType gdm_greeter_get_type (void);
+GdmGreeter * gdm_greeter_new (const char *display_id);
+gboolean gdm_greeter_start (GdmGreeter *greeter);
+gboolean gdm_greeter_stop (GdmGreeter *greeter);
+
+G_END_DECLS
+
+#endif /* __GDM_GREETER_H */
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
new file mode 100644
index 00000000..63b5ca43
--- /dev/null
+++ b/daemon/gdm-manager.c
@@ -0,0 +1,433 @@
+/* -*- 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 <signal.h>
+#include <sys/stat.h>
+#include <sys/types.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-manager.h"
+#include "gdm-manager-glue.h"
+#include "gdm-display-store.h"
+#include "gdm-xdmcp-manager.h"
+#include "gdm-common.h"
+
+#include "gdm-static-display.h"
+
+#include "gdm-master-config.h"
+#include "gdm-daemon-config-entries.h"
+
+#include "cookie.h"
+
+#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
+
+#define GDM_DBUS_PATH "/org/gnome/DisplayManager"
+#define GDM_MANAGER_DBUS_PATH GDM_DBUS_PATH "/Manager"
+#define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.Manager"
+
+struct GdmManagerPrivate
+{
+ GdmDisplayStore *display_store;
+ GdmDaemonConfig *daemon_config;
+ GdmXdmcpManager *xdmcp_manager;
+
+ gboolean xdmcp_enabled;
+
+ char *global_cookie;
+ gboolean wait_for_go;
+ gboolean no_console;
+
+ DBusGProxy *bus_proxy;
+ DBusGConnection *connection;
+};
+
+static void gdm_manager_class_init (GdmManagerClass *klass);
+static void gdm_manager_init (GdmManager *manager);
+static void gdm_manager_finalize (GObject *object);
+
+static gpointer manager_object = NULL;
+
+G_DEFINE_TYPE (GdmManager, gdm_manager, G_TYPE_OBJECT)
+
+GQuark
+gdm_manager_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gdm_manager_error");
+ }
+
+ return ret;
+}
+
+static gboolean
+listify_display_ids (const char *id,
+ GdmDisplay *display,
+ GPtrArray **array)
+{
+ g_ptr_array_add (*array, g_strdup (id));
+
+ /* return FALSE to continue */
+ return FALSE;
+}
+
+/*
+ Example:
+ dbus-send --system --dest=org.gnome.DisplayManager \
+ --type=method_call --print-reply --reply-timeout=2000 \
+ /org/gnome/DisplayManager/Manager \
+ org.gnome.DisplayManager.Manager.GetDisplays
+*/
+gboolean
+gdm_manager_get_displays (GdmManager *manager,
+ GPtrArray **displays,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_MANAGER (manager), FALSE);
+
+ if (displays == NULL) {
+ return FALSE;
+ }
+
+ *displays = g_ptr_array_new ();
+ gdm_display_store_foreach (manager->priv->display_store,
+ (GdmDisplayStoreFunc)listify_display_ids,
+ displays);
+
+ return TRUE;
+}
+
+static gboolean
+start_local_display (const char *id,
+ GdmDisplay *d,
+ GdmManager *manager)
+{
+ gboolean ret;
+
+ ret = TRUE;
+
+ g_assert (d != NULL);
+
+ if (GDM_IS_STATIC_DISPLAY (d) &&
+ gdm_display_get_status (d) == GDM_DISPLAY_UNMANAGED) {
+ if (! gdm_display_manage (d)) {
+ gdm_display_unmanage (d);
+ } else {
+ ret = FALSE;
+ }
+ }
+
+ return ret;
+}
+
+static void
+start_unborn_local_displays (GdmManager *manager)
+{
+ gdm_display_store_foreach (manager->priv->display_store,
+ (GdmDisplayStoreFunc)start_local_display,
+ manager);
+}
+
+static void
+make_global_cookie (GdmManager *manager)
+{
+ FILE *fp;
+ char *file;
+
+ gdm_cookie_generate ((char **)&manager->priv->global_cookie, NULL);
+
+ file = g_build_filename (AUTHDIR, ".cookie", NULL);
+ VE_IGNORE_EINTR (g_unlink (file));
+
+ fp = gdm_safe_fopen_w (file, 077);
+ if G_UNLIKELY (fp == NULL) {
+ g_warning (_("Can't open %s for writing"), file);
+ g_free (file);
+ return;
+ }
+
+ VE_IGNORE_EINTR (fprintf (fp, "%s\n", manager->priv->global_cookie));
+
+ /* FIXME: What about out of disk space errors? */
+ errno = 0;
+ VE_IGNORE_EINTR (fclose (fp));
+ if G_UNLIKELY (errno != 0) {
+ g_warning (_("Can't write to %s: %s"),
+ file,
+ g_strerror (errno));
+ }
+
+ g_free (file);
+}
+
+static void
+load_static_displays_from_file (GdmManager *manager)
+{
+ GSList *xservers;
+ GSList *l;
+
+ xservers = gdm_daemon_config_get_xserver_list (manager->priv->daemon_config);
+
+ for (l = xservers; l != NULL; l = l->next) {
+ GdmXserver *xserver;
+ GdmDisplay *display;
+
+ xserver = l->data;
+
+ g_debug ("Loading display for '%d' %s", xserver->number, xserver->id);
+
+ display = gdm_static_display_new (xserver->number,
+ xserver->id);
+
+ if (display == NULL) {
+ g_warning ("Unable to create display: %d %s", xserver->number, xserver->id);
+ continue;
+ }
+
+ gdm_display_store_add (manager->priv->display_store, display);
+ }
+}
+
+static void
+load_static_servers (GdmManager *manager)
+{
+
+ load_static_displays_from_file (manager);
+}
+
+void
+gdm_manager_start (GdmManager *manager)
+{
+ load_static_servers (manager);
+
+ /* Start static X servers */
+ start_unborn_local_displays (manager);
+
+ /* Accept remote connections */
+ if (manager->priv->xdmcp_enabled && ! manager->priv->wait_for_go) {
+ if (manager->priv->xdmcp_manager != NULL) {
+ g_debug ("Accepting XDMCP connections...");
+ gdm_xdmcp_manager_start (manager->priv->xdmcp_manager, NULL);
+ }
+ }
+
+}
+
+void
+gdm_manager_set_wait_for_go (GdmManager *manager,
+ gboolean wait_for_go)
+{
+ if (manager->priv->wait_for_go != wait_for_go) {
+ manager->priv->wait_for_go = wait_for_go;
+
+ if (! wait_for_go) {
+ /* we got a go */
+
+ if (manager->priv->xdmcp_enabled && manager->priv->xdmcp_manager != NULL) {
+ g_debug ("Accepting XDMCP connections...");
+ gdm_xdmcp_manager_start (manager->priv->xdmcp_manager, NULL);
+ }
+ }
+ }
+}
+
+typedef struct {
+ const char *service_name;
+ GdmManager *manager;
+} RemoveDisplayData;
+
+static gboolean
+remove_display_for_connection (GdmDisplay *display,
+ RemoveDisplayData *data)
+{
+ g_assert (display != NULL);
+ g_assert (data->service_name != NULL);
+
+ /* FIXME: compare service name to that of display */
+#if 0
+ if (strcmp (info->service_name, data->service_name) == 0) {
+ remove_session_for_cookie (data->manager, cookie, NULL);
+ leader_info_cancel (info);
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+
+static void
+remove_displays_for_connection (GdmManager *manager,
+ const char *service_name)
+{
+ RemoveDisplayData data;
+
+ data.service_name = service_name;
+ data.manager = manager;
+
+ g_debug ("Removing display for service name: %s", service_name);
+
+ gdm_display_store_foreach_remove (manager->priv->display_store,
+ (GdmDisplayStoreFunc)remove_display_for_connection,
+ &data);
+}
+
+static void
+bus_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *service_name,
+ const char *old_service_name,
+ const char *new_service_name,
+ GdmManager *manager)
+{
+ if (strlen (new_service_name) == 0) {
+ remove_displays_for_connection (manager, old_service_name);
+ }
+
+ g_debug ("NameOwnerChanged: service_name='%s', old_service_name='%s' new_service_name='%s'",
+ service_name, old_service_name, new_service_name);
+}
+
+static gboolean
+register_manager (GdmManager *manager)
+{
+ GError *error = NULL;
+
+ error = NULL;
+ manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (manager->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+
+ manager->priv->bus_proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ dbus_g_proxy_add_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (bus_name_owner_changed),
+ manager,
+ NULL);
+
+ dbus_g_connection_register_g_object (manager->priv->connection, GDM_MANAGER_DBUS_PATH, G_OBJECT (manager));
+
+ return TRUE;
+}
+
+static void
+gdm_manager_class_init (GdmManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_manager_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmManagerPrivate));
+
+ dbus_g_object_type_install_info (GDM_TYPE_MANAGER, &dbus_glib_gdm_manager_object_info);
+}
+
+static void
+gdm_manager_init (GdmManager *manager)
+{
+
+ manager->priv = GDM_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->daemon_config = gdm_daemon_config_new ();
+
+ make_global_cookie (manager);
+
+ gdm_daemon_config_get_bool_for_id (manager->priv->daemon_config,
+ GDM_ID_XDMCP,
+ &manager->priv->xdmcp_enabled);
+
+ manager->priv->display_store = gdm_display_store_new ();
+
+ if (manager->priv->xdmcp_enabled) {
+ manager->priv->xdmcp_manager = gdm_xdmcp_manager_new (manager->priv->display_store);
+ }
+}
+
+static void
+gdm_manager_finalize (GObject *object)
+{
+ GdmManager *manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_MANAGER (object));
+
+ manager = GDM_MANAGER (object);
+
+ g_return_if_fail (manager->priv != NULL);
+
+ if (manager->priv->xdmcp_manager != NULL) {
+ g_object_unref (manager->priv->xdmcp_manager);
+ }
+
+ gdm_display_store_clear (manager->priv->display_store);
+ g_object_unref (manager->priv->display_store);
+
+ if (manager->priv->daemon_config != NULL) {
+ g_object_unref (manager->priv->daemon_config);
+ }
+
+ G_OBJECT_CLASS (gdm_manager_parent_class)->finalize (object);
+}
+
+GdmManager *
+gdm_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ gboolean res;
+
+ manager_object = g_object_new (GDM_TYPE_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ res = register_manager (manager_object);
+ if (! res) {
+ g_object_unref (manager_object);
+ return NULL;
+ }
+ }
+
+ return GDM_MANAGER (manager_object);
+}
diff --git a/daemon/gdm-manager.h b/daemon/gdm-manager.h
new file mode 100644
index 00000000..5dd091d9
--- /dev/null
+++ b/daemon/gdm-manager.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 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_MANAGER_H
+#define __GDM_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_MANAGER (gdm_manager_get_type ())
+#define GDM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_MANAGER, GdmManager))
+#define GDM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_MANAGER, GdmManagerClass))
+#define GDM_IS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_MANAGER))
+#define GDM_IS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_MANAGER))
+#define GDM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_MANAGER, GdmManagerClass))
+
+typedef struct GdmManagerPrivate GdmManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmManagerPrivate *priv;
+} GdmManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmManagerClass;
+
+typedef enum
+{
+ GDM_MANAGER_ERROR_GENERAL
+} GdmManagerError;
+
+#define GDM_MANAGER_ERROR gdm_manager_error_quark ()
+
+GQuark gdm_manager_error_quark (void);
+GType gdm_manager_get_type (void);
+
+GdmManager * gdm_manager_new (void);
+void gdm_manager_start (GdmManager *manager);
+void gdm_manager_set_wait_for_go (GdmManager *manager,
+ gboolean wait_for_go);
+
+gboolean gdm_manager_get_displays (GdmManager *manager,
+ GPtrArray **displays,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* __GDM_MANAGER_H */
diff --git a/daemon/gdm-manager.xml b/daemon/gdm-manager.xml
new file mode 100644
index 00000000..c59834e7
--- /dev/null
+++ b/daemon/gdm-manager.xml
@@ -0,0 +1,14 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/gnome/DisplayManager/Manager">
+ <interface name="org.gnome.DisplayManager.Manager">
+ <method name="GetDisplays">
+ <arg name="displays" direction="out" type="ao"/>
+ </method>
+ <signal name="DisplayAdded">
+ <arg name="id" type="o"/>
+ </signal>
+ <signal name="DisplayRemoved">
+ <arg name="id" type="o"/>
+ </signal>
+ </interface>
+</node>
diff --git a/daemon/gdm-master-config.c b/daemon/gdm-master-config.c
new file mode 100644
index 00000000..77278c71
--- /dev/null
+++ b/daemon/gdm-master-config.c
@@ -0,0 +1,941 @@
+/* -*- 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 <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h> /* for PRIO_MIN */
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "gdm-config.h"
+#include "gdm-master-config.h"
+#include "gdm-daemon-config-entries.h"
+
+#define GDM_STANDARD "Standard"
+
+/* PRIO_MIN and PRIO_MAX are not defined on Solaris, but are -20 and 20 */
+#if sun
+#ifndef PRIO_MIN
+#define PRIO_MIN -20
+#endif
+#ifndef PRIO_MAX
+#define PRIO_MAX 20
+#endif
+#endif
+
+#define GDM_DAEMON_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DAEMON_CONFIG, GdmDaemonConfigPrivate))
+
+struct GdmDaemonConfigPrivate
+{
+ GdmConfig *config;
+ GSList *xservers;
+
+ char *default_file;
+ char *custom_file;
+};
+
+static void gdm_daemon_config_class_init (GdmDaemonConfigClass *klass);
+static void gdm_daemon_config_init (GdmDaemonConfig *daemon_config);
+static void gdm_daemon_config_finalize (GObject *object);
+
+static gpointer daemon_config_object = NULL;
+
+G_DEFINE_TYPE (GdmDaemonConfig, gdm_daemon_config, G_TYPE_OBJECT)
+
+GQuark
+gdm_daemon_config_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gdm_daemon_config_error");
+ }
+
+ return ret;
+}
+
+/*
+ * gdm_read_default
+ *
+ * This function is used to support systems that have the /etc/default/login
+ * interface to control programs that affect security. This is a Solaris
+ * thing, though some users on other systems may find it useful.
+ */
+static char *
+gdm_read_default (char *key)
+{
+#ifdef HAVE_DEFOPEN
+ gchar *retval = NULL;
+
+ if (defopen ("/etc/default/login") == 0) {
+ int flags = defcntl (DC_GETFLAGS, 0);
+
+ TURNOFF (flags, DC_CASE);
+ (void) defcntl (DC_SETFLAGS, flags); /* ignore case */
+ retval = g_strdup (defread (key));
+ (void) defopen ((char *)NULL);
+ }
+ return retval;
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * gdm_daemon_config_get_bool_for_id
+ *
+ * Gets a boolean configuration option by ID. The option must
+ * first be loaded, say, by calling gdm_daemon_config_parse.
+ */
+gboolean
+gdm_daemon_config_get_bool_for_id (GdmDaemonConfig *config,
+ int id,
+ gboolean *val)
+{
+ return gdm_config_get_bool_for_id (config->priv->config, id, val);
+}
+
+/**
+ * gdm_daemon_config_get_int_for_id
+ *
+ * Gets a integer configuration option by ID. The option must
+ * first be loaded, say, by calling gdm_daemon_config_parse.
+ */
+gboolean
+gdm_daemon_config_get_int_for_id (GdmDaemonConfig *config,
+ int id,
+ int *val)
+{
+ return gdm_config_get_int_for_id (config->priv->config, id, val);
+}
+
+/**
+ * gdm_daemon_config_get_string_for_id
+ *
+ * Gets a string configuration option by ID. The option must
+ * first be loaded, say, by calling gdm_daemon_config_parse.
+ */
+gboolean
+gdm_daemon_config_get_string_for_id (GdmDaemonConfig *config,
+ int id,
+ char **val)
+{
+ return gdm_config_get_string_for_id (config->priv->config, id, val);
+}
+
+static void
+gdm_daemon_config_class_init (GdmDaemonConfigClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_daemon_config_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmDaemonConfigPrivate));
+}
+
+static gboolean
+validate_path (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ char *str;
+
+ /* If the /etc/default has a PATH use that */
+ str = gdm_read_default ("PATH=");
+ if (str != NULL) {
+ gdm_config_value_set_string (value, str);
+ g_free (str);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_root_path (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ char *str;
+
+ /* If the /etc/default has a PATH use that */
+ str = gdm_read_default ("SUPATH=");
+ if (str != NULL) {
+ gdm_config_value_set_string (value, str);
+ g_free (str);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_base_xsession (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+ if (str == NULL || str[0] == '\0') {
+ char *path;
+ path = g_build_filename (GDMCONFDIR, "gdm", "Xsession", NULL);
+ g_debug (_("BaseXsession empty; using %s"), path);
+ gdm_config_value_set_string (value, path);
+ g_free (path);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_power_action (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ /* FIXME: should weed out the commands that don't work */
+
+ return TRUE;
+}
+
+static gboolean
+validate_standard_xserver (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ gboolean res;
+ gboolean is_ok;
+ const char *str;
+ char *new;
+
+ is_ok = FALSE;
+ new = NULL;
+ str = gdm_config_value_get_string (value);
+
+ if (str != NULL) {
+ char **argv;
+
+ if (g_shell_parse_argv (str, NULL, &argv, NULL)) {
+ if (g_access (argv[0], X_OK) == 0) {
+ is_ok = TRUE;
+ }
+ g_strfreev (argv);
+ }
+ }
+
+ if G_UNLIKELY (! is_ok) {
+ g_debug (_("Standard X server not found; trying alternatives"));
+ if (g_access ("/usr/X11R6/bin/X", X_OK) == 0) {
+ new = g_strdup ("/usr/X11R6/bin/X");
+ } else if (g_access ("/opt/X11R6/bin/X", X_OK) == 0) {
+ new = g_strdup ("/opt/X11R6/bin/X");
+ } else if (g_access ("/usr/bin/X11/X", X_OK) == 0) {
+ new = g_strdup ("/usr/bin/X11/X");
+ }
+ }
+
+ if (new != NULL) {
+ gdm_config_value_set_string (value, new);
+ g_free (new);
+ }
+
+ res = TRUE;
+
+ return res;
+}
+
+static gboolean
+validate_graphical_theme_dir (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+
+ if (str == NULL || !g_file_test (str, G_FILE_TEST_IS_DIR)) {
+ gdm_config_value_set_string (value, GREETERTHEMEDIR);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_graphical_theme (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+
+ if (str == NULL || str[0] == '\0') {
+ gdm_config_value_set_string (value, "circles");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_greeter (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+
+ if (str == NULL || str[0] == '\0') {
+ g_warning (_("%s: No greeter specified."), "gdm_config_parse");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_remote_greeter (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+
+ if (str == NULL || str[0] == '\0') {
+ g_warning (_("%s: No remote greeter specified."), "gdm_config_parse");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_session_desktop_dir (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ const char *str;
+
+ str = gdm_config_value_get_string (value);
+
+ if (str == NULL || str[0] == '\0') {
+ g_warning (_("%s: No sessions directory specified."), "gdm_config_parse");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_password_required (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ char *str;
+
+ str = gdm_read_default ("PASSREQ=");
+ if (str != NULL && str[0] == '\0') {
+ gboolean val;
+ val = (g_ascii_strcasecmp (str, "YES") == 0);
+ gdm_config_value_set_bool (value, val);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_allow_remote_root (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+ char *str;
+
+ str = gdm_read_default ("CONSOLE=");
+ if (str != NULL && str[0] == '\0') {
+ gboolean val;
+ val = (g_ascii_strcasecmp (str, "/dev/console") != 0);
+ gdm_config_value_set_bool (value, val);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_xdmcp (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value)
+{
+
+#ifndef HAVE_LIBXDMCP
+ if (gdm_config_value_get_bool (value)) {
+ g_debug (_("XDMCP was enabled while there is no XDMCP support; turning it off"));
+ gdm_config_value_set_bool (value, FALSE);
+ }
+#endif
+
+ return TRUE;
+}
+
+static gboolean
+validate_at_least_int (GdmConfig *config,
+ GdmConfigSourceType source,
+ GdmConfigValue *value,
+ int minval,
+ int defval)
+{
+ if (gdm_config_value_get_int (value) < minval) {
+ gdm_config_value_set_int (value, defval);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_cb (GdmConfig *config,
+ GdmConfigSourceType source,
+ const char *group,
+ const char *key,
+ GdmConfigValue *value,
+ int id,
+ gpointer data)
+{
+ gboolean res;
+
+ res = TRUE;
+
+ switch (id) {
+ case GDM_ID_PATH:
+ res = validate_path (config, source, value);
+ break;
+ case GDM_ID_ROOT_PATH:
+ res = validate_root_path (config, source, value);
+ break;
+ case GDM_ID_BASE_XSESSION:
+ res = validate_base_xsession (config, source, value);
+ break;
+ case GDM_ID_HALT:
+ case GDM_ID_REBOOT:
+ case GDM_ID_SUSPEND:
+ res = validate_power_action (config, source, value);
+ break;
+ case GDM_ID_STANDARD_XSERVER:
+ res = validate_standard_xserver (config, source, value);
+ break;
+ case GDM_ID_GRAPHICAL_THEME_DIR:
+ res = validate_graphical_theme_dir (config, source, value);
+ break;
+ case GDM_ID_GRAPHICAL_THEME:
+ res = validate_graphical_theme (config, source, value);
+ break;
+ case GDM_ID_GREETER:
+ res = validate_greeter (config, source, value);
+ break;
+ case GDM_ID_REMOTE_GREETER:
+ res = validate_remote_greeter (config, source, value);
+ break;
+ case GDM_ID_SESSION_DESKTOP_DIR:
+ res = validate_session_desktop_dir (config, source, value);
+ break;
+ case GDM_ID_PASSWORD_REQUIRED:
+ res = validate_password_required (config, source, value);
+ break;
+ case GDM_ID_ALLOW_REMOTE_ROOT:
+ res = validate_allow_remote_root (config, source, value);
+ break;
+ case GDM_ID_XDMCP:
+ res = validate_xdmcp (config, source, value);
+ break;
+ case GDM_ID_MAX_INDIRECT:
+ case GDM_ID_XINERAMA_SCREEN:
+ res = validate_at_least_int (config, source, value, 0, 0);
+ break;
+ case GDM_ID_TIMED_LOGIN_DELAY:
+ res = validate_at_least_int (config, source, value, 5, 5);
+ break;
+ case GDM_ID_MAX_ICON_WIDTH:
+ case GDM_ID_MAX_ICON_HEIGHT:
+ res = validate_at_least_int (config, source, value, 0, 128);
+ break;
+ case GDM_ID_SCAN_TIME:
+ res = validate_at_least_int (config, source, value, 1, 1);
+ break;
+ case GDM_ID_NONE:
+ case GDM_CONFIG_INVALID_ID:
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static const char *
+source_to_name (GdmConfigSourceType source)
+{
+ const char *name;
+
+ switch (source) {
+ case GDM_CONFIG_SOURCE_DEFAULT:
+ name = "default";
+ break;
+ case GDM_CONFIG_SOURCE_MANDATORY:
+ name = "mandatory";
+ break;
+ case GDM_CONFIG_SOURCE_CUSTOM:
+ name = "custom";
+ break;
+ case GDM_CONFIG_SOURCE_BUILT_IN:
+ name = "built-in";
+ break;
+ case GDM_CONFIG_SOURCE_RUNTIME_USER:
+ name = "runtime-user";
+ break;
+ case GDM_CONFIG_SOURCE_INVALID:
+ name = "Invalid";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ }
+
+ return name;
+}
+
+static gboolean
+notify_cb (GdmConfig *config,
+ GdmConfigSourceType source,
+ const char *group,
+ const char *key,
+ GdmConfigValue *value,
+ int id,
+ gpointer data)
+{
+ char *valstr;
+
+ /* FIXME: need a better approach */
+#if 0
+ switch (id) {
+ case GDM_ID_GREETER:
+ case GDM_ID_REMOTE_GREETER:
+ case GDM_ID_SOUND_ON_LOGIN_FILE:
+ case GDM_ID_SOUND_ON_LOGIN_SUCCESS_FILE:
+ case GDM_ID_SOUND_ON_LOGIN_FAILURE_FILE:
+ case GDM_ID_GTK_MODULES_LIST:
+ case GDM_ID_TIMED_LOGIN:
+ case GDM_ID_ALLOW_ROOT:
+ case GDM_ID_ALLOW_REMOTE_ROOT:
+ case GDM_ID_ALLOW_REMOTE_AUTOLOGIN:
+ case GDM_ID_SYSTEM_MENU:
+ case GDM_ID_CONFIG_AVAILABLE:
+ case GDM_ID_CHOOSER_BUTTON:
+ case GDM_ID_DISALLOW_TCP:
+ case GDM_ID_ADD_GTK_MODULES:
+ case GDM_ID_TIMED_LOGIN_ENABLE:
+ case GDM_ID_RETRY_DELAY:
+ case GDM_ID_TIMED_LOGIN_DELAY:
+ notify_displays_value (config, group, key, value);
+ break;
+ case GDM_ID_NONE:
+ case GDM_CONFIG_INVALID_ID:
+ {
+ /* doesn't have an ID : match group/key */
+ if (group != NULL) {
+ if (strcmp (group, GDM_CONFIG_GROUP_SERVERS) == 0) {
+ /* FIXME: handle this? */
+ } else if (strcmp (group, GDM_CONFIG_GROUP_CUSTOM_CMD) == 0) {
+ notify_displays_value (config, group, key, value);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+
+ valstr = gdm_config_value_to_string (value);
+ g_debug ("Got config %s/%s=%s <%s>\n",
+ group,
+ key,
+ valstr,
+ source_to_name (source));
+ g_free (valstr);
+
+ return TRUE;
+}
+
+/**
+ * gdm_daemon_config_find_xserver
+ *
+ * Return an xserver with a given ID, or NULL if not found.
+ */
+GdmXserver *
+gdm_daemon_config_find_xserver (GdmDaemonConfig *config,
+ const char *id)
+{
+ GSList *li;
+
+ if (config->priv->xservers == NULL) {
+ return NULL;
+ }
+
+ if (id == NULL) {
+ return config->priv->xservers->data;
+ }
+
+ for (li = config->priv->xservers; li != NULL; li = li->next) {
+ GdmXserver *svr = li->data;
+ if (svr->id != NULL && strcmp (svr->id, id) == 0) {
+ return svr;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * gdm_daemon_config_get_xservers
+ *
+ * Prepare a string to be returned for the GET_SERVER_LIST
+ * sockets command.
+ */
+gchar *
+gdm_daemon_config_get_xservers (GdmDaemonConfig *config)
+{
+ GSList *li;
+ char *retval = NULL;
+
+ if (config->priv->xservers == NULL) {
+ return NULL;
+ }
+
+ for (li = config->priv->xservers; li != NULL; li = li->next) {
+ GdmXserver *svr = li->data;
+ if (retval != NULL)
+ retval = g_strconcat (retval, ";", svr->id, NULL);
+ else
+ retval = g_strdup (svr->id);
+ }
+
+ return retval;
+}
+
+/**
+ * gdm_daemon_config_get_xserver_list
+ *
+ * Returns the list of xservers being used.
+ */
+GSList *
+gdm_daemon_config_get_xserver_list (GdmDaemonConfig *config)
+{
+ return config->priv->xservers;
+}
+
+
+static void
+gdm_daemon_config_load_xserver (GdmDaemonConfig *config,
+ const char *key,
+ const char *name)
+{
+ GdmXserver *svr;
+ int n;
+ char *group;
+ gboolean res;
+ GdmConfigValue *value;
+
+ /*
+ * See if we already loaded a server with this id, skip if
+ * one already exists.
+ */
+ if (gdm_daemon_config_find_xserver (config, name) != NULL) {
+ return;
+ }
+
+ svr = g_new0 (GdmXserver, 1);
+ svr->id = g_strdup (name);
+
+ if (isdigit (*key)) {
+ svr->number = atoi (key);
+ }
+
+ group = g_strdup_printf ("server-%s", name);
+
+ /* string */
+ res = gdm_config_get_value (config->priv->config, group, "name", &value);
+ if (res) {
+ svr->name = g_strdup (gdm_config_value_get_string (value));
+ }
+ res = gdm_config_get_value (config->priv->config, group, "command", &value);
+ if (res) {
+ svr->command = g_strdup (gdm_config_value_get_string (value));
+ }
+
+ g_debug ("Adding new server id=%s name=%s command=%s", name, svr->name, svr->command);
+
+
+ /* bool */
+ res = gdm_config_get_value (config->priv->config, group, "flexible", &value);
+ if (res) {
+ svr->flexible = gdm_config_value_get_bool (value);
+ }
+ res = gdm_config_get_value (config->priv->config, group, "choosable", &value);
+ if (res) {
+ svr->choosable = gdm_config_value_get_bool (value);
+ }
+ res = gdm_config_get_value (config->priv->config, group, "handled", &value);
+ if (res) {
+ svr->handled = gdm_config_value_get_bool (value);
+ }
+ res = gdm_config_get_value (config->priv->config, group, "chooser", &value);
+ if (res) {
+ svr->chooser = gdm_config_value_get_bool (value);
+ }
+
+ /* int */
+ res = gdm_config_get_value (config->priv->config, group, "priority", &value);
+ if (res) {
+ svr->priority = gdm_config_value_get_int (value);
+ }
+
+ /* do some bounds checking */
+ n = svr->priority;
+ if (n < PRIO_MIN) {
+ n = PRIO_MIN;
+ } else if (n > PRIO_MAX) {
+ n = PRIO_MAX;
+ }
+
+ if (n != svr->priority) {
+ g_warning (_("%s: Priority out of bounds; changed to %d"),
+ "gdm_config_parse", n);
+ svr->priority = n;
+ }
+
+ if (svr->command == NULL || svr->command[0] == '\0') {
+ g_warning (_("Empty server command; using standard command."));
+ g_free (svr->command);
+ svr->command = g_strdup (X_SERVER);
+ }
+
+ config->priv->xservers = g_slist_append (config->priv->xservers, svr);
+}
+
+static void
+gdm_daemon_config_unload_xservers (GdmDaemonConfig *config)
+{
+ GSList *xli;
+
+ /* Free list if already loaded */
+ for (xli = config->priv->xservers; xli != NULL; xli = xli->next) {
+ GdmXserver *xsvr = xli->data;
+
+ g_free (xsvr->id);
+ g_free (xsvr->name);
+ g_free (xsvr->command);
+ }
+
+ if (config->priv->xservers != NULL) {
+ g_slist_free (config->priv->xservers);
+ config->priv->xservers = NULL;
+ }
+}
+
+static void
+gdm_daemon_config_ensure_one_xserver (GdmDaemonConfig *config)
+{
+ /* If no "Standard" server was created, then add it */
+ if (config->priv->xservers == NULL || gdm_daemon_config_find_xserver (config, GDM_STANDARD) == NULL) {
+ GdmXserver *svr = g_new0 (GdmXserver, 1);
+
+ svr->id = g_strdup (GDM_STANDARD);
+ svr->name = g_strdup ("Standard server");
+ svr->command = g_strdup (X_SERVER);
+ svr->flexible = TRUE;
+ svr->choosable = TRUE;
+ svr->handled = TRUE;
+ svr->priority = 0;
+
+ config->priv->xservers = g_slist_append (config->priv->xservers, svr);
+ }
+}
+
+static void
+load_xservers_group (GdmDaemonConfig *config)
+{
+ char **keys;
+ gsize len;
+ int i;
+
+ keys = gdm_config_get_keys_for_group (config->priv->config, GDM_CONFIG_GROUP_SERVERS, &len, NULL);
+
+ /* now construct entries for these groups */
+ for (i = 0; i < len; i++) {
+ GdmConfigEntry entry;
+ GdmConfigValue *value;
+ char *new_group;
+ gboolean res;
+ int j;
+ const char *name;
+
+ entry.group = GDM_CONFIG_GROUP_SERVERS;
+ entry.key = keys[i];
+ entry.type = GDM_CONFIG_VALUE_STRING;
+ entry.default_value = NULL;
+ entry.id = GDM_CONFIG_INVALID_ID;
+
+ gdm_config_add_entry (config->priv->config, &entry);
+ gdm_config_process_entry (config->priv->config, &entry, NULL);
+
+ res = gdm_config_get_value (config->priv->config, entry.group, entry.key, &value);
+ if (! res) {
+ continue;
+ }
+
+ name = gdm_config_value_get_string (value);
+ if (name == NULL || name[0] == '\0') {
+ gdm_config_value_free (value);
+ continue;
+ }
+
+ /* skip servers marked as inactive */
+ if (g_ascii_strcasecmp (name, "inactive") == 0) {
+ gdm_config_value_free (value);
+ continue;
+ }
+
+ new_group = g_strdup_printf ("server-%s", name);
+ for (j = 0; j < G_N_ELEMENTS (gdm_daemon_server_config_entries); j++) {
+ GdmConfigEntry *srv_entry;
+ if (gdm_daemon_server_config_entries[j].key == NULL) {
+ continue;
+ }
+ srv_entry = gdm_config_entry_copy (&gdm_daemon_server_config_entries[j]);
+ g_free (srv_entry->group);
+ srv_entry->group = g_strdup (new_group);
+ gdm_config_process_entry (config->priv->config, srv_entry, NULL);
+ gdm_config_entry_free (srv_entry);
+ }
+ g_free (new_group);
+
+ /* now we can add this server */
+ gdm_daemon_config_load_xserver (config, entry.key, gdm_config_value_get_string (value));
+
+ gdm_config_value_free (value);
+ }
+}
+
+static void
+gdm_daemon_config_load_xservers (GdmDaemonConfig *config)
+{
+ gdm_daemon_config_unload_xservers (config);
+ load_xservers_group (config);
+ gdm_daemon_config_ensure_one_xserver (config);
+}
+
+static void
+load_config (GdmDaemonConfig *config)
+{
+ GError *error;
+
+ config->priv->config = gdm_config_new ();
+
+ gdm_config_set_notify_func (config->priv->config, notify_cb, NULL);
+ gdm_config_set_validate_func (config->priv->config, validate_cb, NULL);
+
+ gdm_config_add_static_entries (config->priv->config, gdm_daemon_config_entries);
+
+ gdm_config_set_default_file (config->priv->config, config->priv->default_file);
+ gdm_config_set_custom_file (config->priv->config, config->priv->custom_file);
+
+ /* load the data files */
+ error = NULL;
+ gdm_config_load (config->priv->config, &error);
+ if (error != NULL) {
+ g_warning ("Unable to load configuration: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* populate the database with all specified entries */
+ gdm_config_process_all (config->priv->config, &error);
+
+ gdm_daemon_config_load_xservers (config);
+}
+
+void
+gdm_daemon_config_load (GdmDaemonConfig *config)
+{
+ g_return_if_fail (GDM_IS_DAEMON_CONFIG (config));
+
+ if (config->priv->config != NULL) {
+ return;
+ }
+
+ load_config (config);
+}
+
+static void
+gdm_daemon_config_init (GdmDaemonConfig *config)
+{
+
+ config->priv = GDM_DAEMON_CONFIG_GET_PRIVATE (config);
+
+ config->priv->default_file = GDM_DEFAULTS_CONF;
+ config->priv->custom_file = GDM_CUSTOM_CONF;
+}
+
+static void
+gdm_daemon_config_finalize (GObject *object)
+{
+ GdmDaemonConfig *config;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_DAEMON_CONFIG (object));
+
+ config = GDM_DAEMON_CONFIG (object);
+
+ g_return_if_fail (config->priv != NULL);
+
+ if (config->priv->xservers != NULL) {
+ g_slist_free (config->priv->xservers);
+ }
+
+ G_OBJECT_CLASS (gdm_daemon_config_parent_class)->finalize (object);
+}
+
+GdmDaemonConfig *
+gdm_daemon_config_new (void)
+{
+ if (daemon_config_object != NULL) {
+ g_object_ref (daemon_config_object);
+ } else {
+ daemon_config_object = g_object_new (GDM_TYPE_DAEMON_CONFIG, NULL);
+ g_object_add_weak_pointer (daemon_config_object,
+ (gpointer *) &daemon_config_object);
+ }
+
+ return GDM_DAEMON_CONFIG (daemon_config_object);
+}
diff --git a/daemon/gdm-master-config.h b/daemon/gdm-master-config.h
new file mode 100644
index 00000000..54e1f8a7
--- /dev/null
+++ b/daemon/gdm-master-config.h
@@ -0,0 +1,93 @@
+/* -*- 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_DAEMON_CONFIG_H
+#define __GDM_DAEMON_CONFIG_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_DAEMON_CONFIG (gdm_daemon_config_get_type ())
+#define GDM_DAEMON_CONFIG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DAEMON_CONFIG, GdmDaemonConfig))
+#define GDM_DAEMON_CONFIG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DAEMON_CONFIG, GdmDaemonConfigClass))
+#define GDM_IS_DAEMON_CONFIG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DAEMON_CONFIG))
+#define GDM_IS_DAEMON_CONFIG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DAEMON_CONFIG))
+#define GDM_DAEMON_CONFIG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DAEMON_CONFIG, GdmDaemonConfigClass))
+
+typedef struct GdmDaemonConfigPrivate GdmDaemonConfigPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmDaemonConfigPrivate *priv;
+} GdmDaemonConfig;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmDaemonConfigClass;
+
+typedef enum
+{
+ GDM_DAEMON_CONFIG_ERROR_GENERAL
+} GdmDaemonConfigError;
+
+#define GDM_DAEMON_CONFIG_ERROR gdm_daemon_config_error_quark ()
+
+typedef struct _GdmXserver GdmXserver;
+
+struct _GdmXserver
+{
+ char *id;
+ char *name;
+ char *command;
+ gboolean flexible;
+ gboolean choosable; /* not implemented yet */
+ gboolean chooser; /* instead of greeter, run chooser */
+ gboolean handled;
+ int number;
+ int priority;
+};
+
+GQuark gdm_daemon_config_error_quark (void);
+GType gdm_daemon_config_get_type (void);
+
+GdmDaemonConfig * gdm_daemon_config_new (void);
+void gdm_daemon_config_load (GdmDaemonConfig *config);
+gboolean gdm_daemon_config_get_bool_for_id (GdmDaemonConfig *config,
+ int id,
+ gboolean *value);
+gboolean gdm_daemon_config_get_int_for_id (GdmDaemonConfig *config,
+ int id,
+ int *value);
+gboolean gdm_daemon_config_get_string_for_id (GdmDaemonConfig *config,
+ int id,
+ char **value);
+
+GdmXserver * gdm_daemon_config_find_xserver (GdmDaemonConfig *config,
+ const char *id);
+char * gdm_daemon_config_get_xservers (GdmDaemonConfig *config);
+GSList * gdm_daemon_config_get_xserver_list (GdmDaemonConfig *config);
+
+G_END_DECLS
+
+#endif /* __GDM_DAEMON_CONFIG_H */
diff --git a/daemon/gdm-net.c b/daemon/gdm-net.c
index 93a48dbe..304fe84e 100644
--- a/daemon/gdm-net.c
+++ b/daemon/gdm-net.c
@@ -109,7 +109,7 @@ struct _GdmConnection {
GdmDisplay *disp;
};
-int
+int
gdm_connection_is_server_busy (GdmConnection *conn) {
int max_connections = MAX_CONNECTIONS;
@@ -391,14 +391,15 @@ try_again:
conn->subconnections = NULL;
conn->n_subconnections = 0;
+ gdm_fd_set_close_on_exec (conn->fd);
+
unixchan = g_io_channel_unix_new (conn->fd);
g_io_channel_set_encoding (unixchan, NULL, NULL);
g_io_channel_set_buffered (unixchan, FALSE);
- conn->source = g_io_add_watch_full
- (unixchan, G_PRIORITY_DEFAULT,
- G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- gdm_socket_handler, conn, NULL);
+ conn->source = g_io_add_watch_full (unixchan, G_PRIORITY_DEFAULT,
+ G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+ gdm_socket_handler, conn, NULL);
g_io_channel_unref (unixchan);
listen (fd, 5);
@@ -428,6 +429,8 @@ gdm_connection_open_fd (int fd)
conn->subconnections = NULL;
conn->n_subconnections = 0;
+ gdm_fd_set_close_on_exec (conn->fd);
+
unixchan = g_io_channel_unix_new (conn->fd);
g_io_channel_set_encoding (unixchan, NULL, NULL);
g_io_channel_set_buffered (unixchan, FALSE);
@@ -480,6 +483,8 @@ gdm_connection_open_fifo (const char *fifo, mode_t mode)
conn->subconnections = NULL;
conn->n_subconnections = 0;
+ gdm_fd_set_close_on_exec (conn->fd);
+
fifochan = g_io_channel_unix_new (conn->fd);
g_io_channel_set_encoding (fifochan, NULL, NULL);
g_io_channel_set_buffered (fifochan, FALSE);
@@ -679,4 +684,3 @@ gdm_kill_subconnections_with_display (GdmConnection *conn,
}
}
-/* EOF */
diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c
new file mode 100644
index 00000000..11701c7d
--- /dev/null
+++ b/daemon/gdm-server.c
@@ -0,0 +1,708 @@
+/* -*- 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>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+
+#include "gdm-server.h"
+
+extern char **environ;
+
+#define GDM_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SERVER, GdmServerPrivate))
+
+/* These are the servstat values, also used as server
+ * process exit codes */
+#define SERVER_TIMEOUT 2 /* Server didn't start */
+#define SERVER_DEAD 250 /* Server stopped */
+#define SERVER_PENDING 251 /* Server started but not ready for connections yet */
+#define SERVER_RUNNING 252 /* Server running and ready for connections */
+#define SERVER_ABORT 253 /* Server failed badly. Suspending display. */
+
+struct GdmServerPrivate
+{
+ char *command;
+ GPid pid;
+
+ gboolean disable_tcp;
+ int priority;
+ uid_t uid;
+ char *session_args;
+
+ char *log_dir;
+ char *display_name;
+ char *auth_file;
+
+ gboolean is_parented;
+ char *parent_display_name;
+ char *parent_auth_file;
+ char *chosen_hostname;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_NAME,
+ PROP_AUTH_FILE,
+ PROP_IS_PARENTED,
+ PROP_PARENT_DISPLAY_NAME,
+ PROP_PARENT_AUTH_FILE,
+ PROP_CHOSEN_HOSTNAME,
+ PROP_COMMAND,
+ PROP_PRIORITY,
+ PROP_UID,
+ PROP_SESSION_ARGS,
+ PROP_LOG_DIR,
+ PROP_DISABLE_TCP,
+};
+
+static void gdm_server_class_init (GdmServerClass *klass);
+static void gdm_server_init (GdmServer *server);
+static void gdm_server_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmServer, gdm_server, G_TYPE_OBJECT)
+
+gboolean
+gdm_server_stop (GdmServer *server)
+{
+ g_debug ("Stopping server");
+
+ return TRUE;
+}
+
+/* We keep a connection (parent_dsp) open with the parent X server
+ * before running a proxy on it to prevent the X server resetting
+ * as we open and close other connections.
+ * Note that XDMCP servers, by default, reset when the seed X
+ * connection closes whereas usually the X server only quits when
+ * all X connections have closed.
+ */
+#if 0
+static gboolean
+connect_to_parent (GdmServer *server)
+{
+ int maxtries;
+ int openretries;
+
+ g_debug ("gdm_server_start: Connecting to parent display \'%s\'",
+ d->parent_disp);
+
+ d->parent_dsp = NULL;
+
+ maxtries = SERVER_IS_XDMCP (d) ? 10 : 2;
+
+ openretries = 0;
+ while (openretries < maxtries &&
+ d->parent_dsp == NULL) {
+ d->parent_dsp = XOpenDisplay (d->parent_disp);
+
+ if G_UNLIKELY (d->parent_dsp == NULL) {
+ g_debug ("gdm_server_start: Sleeping %d on a retry", 1+openretries*2);
+ gdm_sleep_no_signal (1+openretries*2);
+ openretries++;
+ }
+ }
+
+ if (d->parent_dsp == NULL)
+ gdm_error (_("%s: failed to connect to parent display \'%s\'"),
+ "gdm_server_start", d->parent_disp);
+
+ return d->parent_dsp != NULL;
+}
+#endif
+
+static gboolean
+gdm_server_resolve_command_line (GdmServer *server,
+ const char *vtarg,
+ int *argcp,
+ char ***argvp)
+{
+ int argc;
+ char **argv;
+ int len;
+ int i;
+ gboolean gotvtarg = FALSE;
+ gboolean query_in_arglist = FALSE;
+
+ g_shell_parse_argv (server->priv->command, &argc, &argv, NULL);
+
+ for (len = 0; argv != NULL && argv[len] != NULL; len++) {
+ char *arg = argv[len];
+
+ /* HACK! Not to add vt argument to servers that already force
+ * allocation. Mostly for backwards compat only */
+ if (strncmp (arg, "vt", 2) == 0 &&
+ isdigit (arg[2]) &&
+ (arg[3] == '\0' ||
+ (isdigit (arg[3]) && arg[4] == '\0')))
+ gotvtarg = TRUE;
+ if (strcmp (arg, "-query") == 0 ||
+ strcmp (arg, "-indirect") == 0)
+ query_in_arglist = TRUE;
+ }
+
+ argv = g_renew (char *, argv, len + 10);
+ /* shift args down one */
+ for (i = len - 1; i >= 1; i--) {
+ argv[i+1] = argv[i];
+ }
+
+ /* server number is the FIRST argument, before any others */
+ argv[1] = g_strdup (server->priv->display_name);
+ len++;
+
+ if (server->priv->auth_file != NULL) {
+ argv[len++] = g_strdup ("-auth");
+ argv[len++] = g_strdup (server->priv->auth_file);
+ }
+
+ if (server->priv->chosen_hostname) {
+ /* run just one session */
+ argv[len++] = g_strdup ("-terminate");
+ argv[len++] = g_strdup ("-query");
+ argv[len++] = g_strdup (server->priv->chosen_hostname);
+ query_in_arglist = TRUE;
+ }
+
+ if (server->priv->disable_tcp && ! query_in_arglist) {
+ argv[len++] = g_strdup ("-nolisten");
+ argv[len++] = g_strdup ("tcp");
+ }
+
+ if (vtarg != NULL && ! gotvtarg) {
+ argv[len++] = g_strdup (vtarg);
+ }
+
+ argv[len++] = NULL;
+
+ *argvp = argv;
+ *argcp = len;
+
+ return TRUE;
+}
+
+/* somewhat safer rename (safer if the log dir is unsafe), may in fact
+ lose the file though, it guarantees that a is gone, but not that
+ b exists */
+static void
+safer_rename (const char *a, const char *b)
+{
+ errno = 0;
+ if (link (a, b) < 0) {
+ if (errno == EEXIST) {
+ VE_IGNORE_EINTR (g_unlink (a));
+ return;
+ }
+ VE_IGNORE_EINTR (g_unlink (b));
+ /* likely this system doesn't support hard links */
+ g_rename (a, b);
+ VE_IGNORE_EINTR (g_unlink (a));
+ return;
+ }
+ VE_IGNORE_EINTR (g_unlink (a));
+}
+
+static void
+rotate_logs (GdmServer *server)
+{
+ const char *dname;
+ const char *logdir;
+
+ dname = server->priv->display_name;
+ logdir = server->priv->log_dir;
+
+ /* I'm too lazy to write a loop */
+ char *fname4 = gdm_make_filename (logdir, dname, ".log.4");
+ char *fname3 = gdm_make_filename (logdir, dname, ".log.3");
+ char *fname2 = gdm_make_filename (logdir, dname, ".log.2");
+ char *fname1 = gdm_make_filename (logdir, dname, ".log.1");
+ char *fname = gdm_make_filename (logdir, dname, ".log");
+
+ /* Rotate the logs (keep 4 last) */
+ VE_IGNORE_EINTR (g_unlink (fname4));
+ safer_rename (fname3, fname4);
+ safer_rename (fname2, fname3);
+ safer_rename (fname1, fname2);
+ safer_rename (fname, fname1);
+
+ g_free (fname4);
+ g_free (fname3);
+ g_free (fname2);
+ g_free (fname1);
+ g_free (fname);
+}
+
+static void
+change_user (GdmServer *server)
+{
+ if (server->priv->uid != 0) {
+ struct passwd *pwent;
+
+ pwent = getpwuid (server->priv->uid);
+ if (pwent == NULL) {
+ g_warning (_("%s: Server was to be spawned by uid %d but "
+ "that user doesn't exist"),
+ "gdm_server_spawn",
+ (int)server->priv->uid);
+ _exit (SERVER_ABORT);
+ }
+
+ if (setgid (pwent->pw_gid) < 0) {
+ g_warning (_("%s: Couldn't set groupid to %d"),
+ "gdm_server_spawn", (int)pwent->pw_gid);
+ _exit (SERVER_ABORT);
+ }
+
+ if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
+ g_warning (_("%s: initgroups () failed for %s"),
+ "gdm_server_spawn", pwent->pw_name);
+ _exit (SERVER_ABORT);
+ }
+
+ if (setuid (server->priv->uid) < 0) {
+ g_warning (_("%s: Couldn't set userid to %d"),
+ "gdm_server_spawn", (int)server->priv->uid);
+ _exit (SERVER_ABORT);
+ }
+ } else {
+ gid_t groups[1] = { 0 };
+
+ if (setgid (0) < 0) {
+ g_warning (_("%s: Couldn't set groupid to 0"),
+ "gdm_server_spawn");
+ /* Don't error out, it's not fatal, if it fails we'll
+ * just still be */
+ }
+ /* this will get rid of any suplementary groups etc... */
+ setgroups (1, groups);
+ }
+}
+
+static void
+server_child_setup (GdmServer *server)
+{
+ char *logfile;
+ int logfd;
+ struct sigaction ign_signal;
+ sigset_t mask;
+
+ /* Rotate the X server logs */
+ rotate_logs (server);
+
+ /* Log all output from spawned programs to a file */
+ logfile = gdm_make_filename (server->priv->log_dir,
+ server->priv->display_name,
+ ".log");
+ VE_IGNORE_EINTR (g_unlink (logfile));
+ VE_IGNORE_EINTR (logfd = open (logfile, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL, 0644));
+
+ if (logfd != -1) {
+ VE_IGNORE_EINTR (dup2 (logfd, 1));
+ VE_IGNORE_EINTR (dup2 (logfd, 2));
+ close (logfd);
+ } else {
+ g_warning (_("%s: Could not open logfile for display %s!"),
+ "gdm_server_spawn",
+ server->priv->display_name);
+ }
+
+ /* The X server expects USR1/TTIN/TTOU to be SIG_IGN */
+ ign_signal.sa_handler = SIG_IGN;
+ ign_signal.sa_flags = SA_RESTART;
+ sigemptyset (&ign_signal.sa_mask);
+
+ if (sigaction (SIGUSR1, &ign_signal, NULL) < 0) {
+ g_warning (_("%s: Error setting %s to %s"),
+ "gdm_server_spawn", "USR1", "SIG_IGN");
+ _exit (SERVER_ABORT);
+ }
+
+ if (sigaction (SIGTTIN, &ign_signal, NULL) < 0) {
+ g_warning (_("%s: Error setting %s to %s"),
+ "gdm_server_spawn", "TTIN", "SIG_IGN");
+ _exit (SERVER_ABORT);
+ }
+
+ if (sigaction (SIGTTOU, &ign_signal, NULL) < 0) {
+ g_warning (_("%s: Error setting %s to %s"),
+ "gdm_server_spawn", "TTOU", "SIG_IGN");
+ _exit (SERVER_ABORT);
+ }
+
+ /* And HUP and TERM are at SIG_DFL from gdm_unset_signals,
+ we also have an empty mask and all that fun stuff */
+
+ /* unblock signals (especially HUP/TERM/USR1) so that we
+ * can control the X server */
+ sigemptyset (&mask);
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ if (server->priv->priority != 0) {
+ if (setpriority (PRIO_PROCESS, 0, server->priv->priority)) {
+ g_warning (_("%s: Server priority couldn't be set to %d: %s"),
+ "gdm_server_spawn",
+ server->priv->priority,
+ g_strerror (errno));
+ }
+ }
+
+ setpgid (0, 0);
+
+ change_user (server);
+
+#if sun
+ {
+ /* Remove old communication pipe, if present */
+ char old_pipe[MAXPATHLEN];
+
+ sprintf (old_pipe, "%s/%d", SDTLOGIN_DIR, server->priv->display_name);
+ g_unlink (old_pipe);
+ }
+#endif
+}
+
+static void
+listify_hash (const char *key,
+ const char *value,
+ GPtrArray *env)
+{
+ char *str;
+ str = g_strdup_printf ("%s=%s", key, value);
+ g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_server_environment (GdmServer *server)
+{
+ GPtrArray *env;
+ char **l;
+ GHashTable *hash;
+
+ 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);
+ for (l = environ; *l != NULL; l++) {
+ char **str;
+ str = g_strsplit (*l, "=", 2);
+ g_hash_table_insert (hash, str[0], str[1]);
+ }
+
+ /* modify environment here */
+ if (server->priv->is_parented) {
+ if (server->priv->parent_auth_file != NULL) {
+ g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (server->priv->parent_auth_file));
+ }
+
+ if (server->priv->parent_display_name != NULL) {
+ g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (server->priv->parent_display_name));
+ }
+ } else {
+ g_hash_table_insert (hash, g_strdup ("DISPLAY="), g_strdup (server->priv->display_name));
+ }
+
+ if (server->priv->uid != 0) {
+ struct passwd *pwent;
+
+ pwent = getpwuid (server->priv->uid);
+
+ if (pwent->pw_dir != NULL
+ && g_file_test (pwent->pw_dir, G_FILE_TEST_EXISTS)) {
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
+ } else {
+ /* Hack */
+ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
+ }
+ g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
+ 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 void
+server_add_xserver_args (GdmServer *server,
+ int *argc,
+ char ***argv)
+{
+ int count;
+ char **args;
+ int len;
+ int i;
+
+ len = *argc;
+ g_shell_parse_argv (server->priv->session_args, &count, &args, NULL);
+ *argv = g_renew (char *, *argv, len + count + 1);
+
+ for (i=0; i < count;i++) {
+ *argv[len++] = g_strdup (args[i]);
+ }
+
+ *argc += count;
+
+ argv[len] = NULL;
+ g_strfreev (args);
+}
+
+static gboolean
+gdm_server_spawn (GdmServer *server,
+ const char *vtarg)
+{
+ int argc;
+ gchar **argv = NULL;
+ GError *error;
+ GPtrArray *env;
+ gboolean ret;
+
+ ret = FALSE;
+
+ /* Figure out the server command */
+ argv = NULL;
+ argc = 0;
+ gdm_server_resolve_command_line (server,
+ vtarg,
+ &argc,
+ &argv);
+
+ if (server->priv->session_args) {
+ server_add_xserver_args (server, &argc, &argv);
+ }
+
+ if (argv[0] == NULL) {
+ g_warning (_("%s: Empty server command for display %s"),
+ "gdm_server_spawn",
+ server->priv->display_name);
+ _exit (SERVER_ABORT);
+ }
+
+ env = get_server_environment (server);
+
+ g_debug ("Starting X server process");
+ error = NULL;
+ ret = g_spawn_async_with_pipes (NULL,
+ argv,
+ (char **)env->pdata,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ (GSpawnChildSetupFunc)server_child_setup,
+ server,
+ &server->priv->pid,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+
+ if (! ret) {
+ g_warning ("Could not start command '%s': %s",
+ server->priv->command,
+ error->message);
+ g_error_free (error);
+ }
+
+ g_strfreev (argv);
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+
+ return ret;
+}
+
+/**
+ * gdm_server_start:
+ * @disp: Pointer to a GdmDisplay structure
+ *
+ * Starts a local X server. Handles retries and fatal errors properly.
+ */
+
+gboolean
+gdm_server_start (GdmServer *server)
+{
+ char *vtarg = NULL;
+ int vtfd = -1;
+ int vt = -1;
+ gboolean res;
+
+#if 0
+ if (d->type == TYPE_XDMCP_PROXY &&
+ ! connect_to_parent (d))
+ return FALSE;
+#endif
+
+#if 0
+ if (d->type == TYPE_STATIC ||
+ d->type == TYPE_FLEXI) {
+ vtarg = gdm_get_empty_vt_argument (&vtfd, &vt);
+ }
+#endif
+
+ /* fork X server process */
+ res = gdm_server_spawn (server, vtarg);
+
+#if 0
+ /* If we were holding a vt open for the server, close it now as it has
+ * already taken the bait. */
+ if (vtfd > 0) {
+ VE_IGNORE_EINTR (close (vtfd));
+ }
+#endif
+
+ return res;
+}
+
+static void
+_gdm_server_set_display_name (GdmServer *server,
+ const char *name)
+{
+ g_free (server->priv->display_name);
+ server->priv->display_name = g_strdup (name);
+}
+
+static void
+gdm_server_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmServer *self;
+
+ self = GDM_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_NAME:
+ _gdm_server_set_display_name (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_server_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmServer *self;
+
+ self = GDM_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, self->priv->display_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_server_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmServer *server;
+ GdmServerClass *klass;
+
+ klass = GDM_SERVER_CLASS (g_type_class_peek (GDM_TYPE_SERVER));
+
+ server = GDM_SERVER (G_OBJECT_CLASS (gdm_server_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ return G_OBJECT (server);
+}
+
+static void
+gdm_server_class_init (GdmServerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_server_get_property;
+ object_class->set_property = gdm_server_set_property;
+ object_class->constructor = gdm_server_constructor;
+ object_class->finalize = gdm_server_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmServerPrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "name",
+ "name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdm_server_init (GdmServer *server)
+{
+
+ server->priv = GDM_SERVER_GET_PRIVATE (server);
+
+ server->priv->pid = -1;
+}
+
+static void
+gdm_server_finalize (GObject *object)
+{
+ GdmServer *server;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_SERVER (object));
+
+ server = GDM_SERVER (object);
+
+ g_return_if_fail (server->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_server_parent_class)->finalize (object);
+}
+
+GdmServer *
+gdm_server_new (const char *display_name)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_SERVER,
+ "display-name", display_name,
+ NULL);
+
+ return GDM_SERVER (object);
+}
diff --git a/daemon/gdm-server.h b/daemon/gdm-server.h
new file mode 100644
index 00000000..fdb55b29
--- /dev/null
+++ b/daemon/gdm-server.h
@@ -0,0 +1,57 @@
+/* -*- 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_SERVER_H
+#define __GDM_SERVER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SERVER (gdm_server_get_type ())
+#define GDM_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SERVER, GdmServer))
+#define GDM_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SERVER, GdmServerClass))
+#define GDM_IS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SERVER))
+#define GDM_IS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SERVER))
+#define GDM_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SERVER, GdmServerClass))
+
+typedef struct GdmServerPrivate GdmServerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmServerPrivate *priv;
+} GdmServer;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+} GdmServerClass;
+
+GType gdm_server_get_type (void);
+GdmServer * gdm_server_new (const char *display_id);
+gboolean gdm_server_start (GdmServer *server);
+gboolean gdm_server_stop (GdmServer *server);
+
+G_END_DECLS
+
+#endif /* __GDM_SERVER_H */
diff --git a/daemon/gdm-slave-proxy.c b/daemon/gdm-slave-proxy.c
new file mode 100644
index 00000000..3b3f1dab
--- /dev/null
+++ b/daemon/gdm-slave-proxy.c
@@ -0,0 +1,441 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#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"
+
+struct GdmSlaveProxyPrivate
+{
+ char *display_id;
+ GPid pid;
+ guint output_watch_id;
+ guint error_watch_id;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_ID,
+};
+
+static void gdm_slave_proxy_class_init (GdmSlaveProxyClass *klass);
+static void gdm_slave_proxy_init (GdmSlaveProxy *slave);
+static void gdm_slave_proxy_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmSlaveProxy, gdm_slave_proxy, G_TYPE_OBJECT)
+
+/* adapted from gspawn.c */
+static int
+wait_on_child (int pid)
+{
+ int status;
+
+ wait_again:
+ if (waitpid (pid, &status, 0) < 0) {
+ if (errno == EINTR) {
+ goto wait_again;
+ } else if (errno == ECHILD) {
+ ; /* do nothing, child already reaped */
+ } else {
+ g_debug ("waitpid () should not fail in 'GdmSpawnProxy'");
+ }
+ }
+
+ return status;
+}
+
+static void
+slave_died (GdmSlaveProxy *slave)
+{
+ int exit_status;
+
+ g_debug ("Waiting on process %d", slave->priv->pid);
+ exit_status = wait_on_child (slave->priv->pid);
+
+ if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
+ g_debug ("Wait on child process failed");
+ } else {
+ /* exited normally */
+ }
+
+ g_spawn_close_pid (slave->priv->pid);
+ slave->priv->pid = -1;
+
+ g_debug ("Slave died");
+}
+
+static gboolean
+output_watch (GIOChannel *source,
+ GIOCondition condition,
+ GdmSlaveProxy *slave)
+{
+ gboolean finished = FALSE;
+
+ if (condition & G_IO_IN) {
+ GIOStatus status;
+ GError *error = NULL;
+ char *line;
+
+ line = NULL;
+ status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
+
+ 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);
+ }
+ }
+ break;
+ case G_IO_STATUS_EOF:
+ finished = TRUE;
+ break;
+ case G_IO_STATUS_ERROR:
+ finished = TRUE;
+ g_debug ("Error reading from child: %s\n", error->message);
+ return FALSE;
+ case G_IO_STATUS_AGAIN:
+ default:
+ break;
+ }
+
+ g_free (line);
+ } else if (condition & G_IO_HUP) {
+ finished = TRUE;
+ }
+
+ if (finished) {
+ slave_died (slave);
+
+ slave->priv->output_watch_id = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* just for debugging */
+static gboolean
+error_watch (GIOChannel *source,
+ GIOCondition condition,
+ GdmSlaveProxy *slave)
+{
+ gboolean finished = FALSE;
+
+ if (condition & G_IO_IN) {
+ GIOStatus status;
+ GError *error = NULL;
+ char *line;
+
+ line = NULL;
+ status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
+
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ g_debug ("command error output: %s", line);
+ break;
+ case G_IO_STATUS_EOF:
+ finished = TRUE;
+ break;
+ case G_IO_STATUS_ERROR:
+ finished = TRUE;
+ g_debug ("Error reading from child: %s\n", error->message);
+ return FALSE;
+ case G_IO_STATUS_AGAIN:
+ default:
+ break;
+ }
+ g_free (line);
+ } else if (condition & G_IO_HUP) {
+ finished = TRUE;
+ }
+
+ if (finished) {
+ slave->priv->error_watch_id = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+spawn_slave (GdmSlaveProxy *slave)
+{
+ char *command;
+ char **argv;
+ gboolean result;
+ GIOChannel *channel;
+ GError *error = NULL;
+ int standard_output;
+ int standard_error;
+
+
+ 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)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_debug ("Running command: %s", command);
+
+ error = NULL;
+ result = g_spawn_async_with_pipes (NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &slave->priv->pid,
+ NULL,
+ &standard_output,
+ &standard_error,
+ &error);
+
+ if (! result) {
+ g_warning ("Could not start command '%s': %s", command, error->message);
+ g_error_free (error);
+ g_strfreev (argv);
+ goto out;
+ }
+
+ g_strfreev (argv);
+
+ /* output channel */
+ channel = g_io_channel_unix_new (standard_output);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+ g_io_channel_set_flags (channel,
+ g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
+ NULL);
+ slave->priv->output_watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc)output_watch,
+ slave);
+ g_io_channel_unref (channel);
+
+ /* error channel */
+ channel = g_io_channel_unix_new (standard_error);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+ g_io_channel_set_flags (channel,
+ g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
+ NULL);
+ slave->priv->error_watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc)error_watch,
+ slave);
+ g_io_channel_unref (channel);
+
+ result = TRUE;
+
+ out:
+ g_free (command);
+
+ return result;
+}
+
+static int
+signal_pid (int pid,
+ int signal)
+{
+ int status = -1;
+
+ /* perhaps block sigchld */
+
+ status = kill (pid, signal);
+
+ if (status < 0) {
+ if (errno == ESRCH) {
+ g_warning ("Child process %lu was already dead.",
+ (unsigned long) pid);
+ } else {
+ g_warning ("Couldn't kill child process %lu: %s",
+ (unsigned long) pid,
+ g_strerror (errno));
+ }
+ }
+
+ /* perhaps unblock sigchld */
+
+ return status;
+}
+
+static void
+kill_slave (GdmSlaveProxy *slave)
+{
+ if (slave->priv->pid <= 1) {
+ return;
+ }
+
+ signal_pid (slave->priv->pid, SIGTERM);
+
+ /* watch should call slave_died */
+}
+
+gboolean
+gdm_slave_proxy_start (GdmSlaveProxy *slave)
+{
+ spawn_slave (slave);
+
+ return TRUE;
+}
+
+gboolean
+gdm_slave_proxy_stop (GdmSlaveProxy *slave)
+{
+ kill_slave (slave);
+
+ return TRUE;
+}
+
+static void
+_gdm_slave_proxy_set_display_id (GdmSlaveProxy *slave,
+ const char *id)
+{
+ g_free (slave->priv->display_id);
+ slave->priv->display_id = g_strdup (id);
+}
+
+static void
+gdm_slave_proxy_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSlaveProxy *self;
+
+ self = GDM_SLAVE_PROXY (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_ID:
+ _gdm_slave_proxy_set_display_id (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_slave_proxy_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSlaveProxy *self;
+
+ self = GDM_SLAVE_PROXY (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_ID:
+ g_value_set_string (value, self->priv->display_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_slave_proxy_class_init (GdmSlaveProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_slave_proxy_get_property;
+ object_class->set_property = gdm_slave_proxy_set_property;
+ object_class->finalize = gdm_slave_proxy_finalize;
+
+ 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",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+}
+
+static void
+gdm_slave_proxy_init (GdmSlaveProxy *slave)
+{
+
+ slave->priv = GDM_SLAVE_PROXY_GET_PRIVATE (slave);
+
+ slave->priv->pid = -1;
+}
+
+static void
+gdm_slave_proxy_finalize (GObject *object)
+{
+ GdmSlaveProxy *slave;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_SLAVE (object));
+
+ slave = GDM_SLAVE_PROXY (object);
+
+ g_return_if_fail (slave->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_slave_proxy_parent_class)->finalize (object);
+}
+
+GdmSlaveProxy *
+gdm_slave_proxy_new (const char *id)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_SLAVE,
+ "display-id", id,
+ NULL);
+
+ return GDM_SLAVE_PROXY (object);
+}
diff --git a/daemon/gdm-slave-proxy.h b/daemon/gdm-slave-proxy.h
new file mode 100644
index 00000000..ff45790a
--- /dev/null
+++ b/daemon/gdm-slave-proxy.h
@@ -0,0 +1,57 @@
+/* -*- 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_SLAVE_PROXY_H
+#define __GDM_SLAVE_PROXY_H
+
+#include <glib-object.h>
+
+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))
+
+typedef struct GdmSlaveProxyPrivate GdmSlaveProxyPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmSlaveProxyPrivate *priv;
+} GdmSlaveProxy;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+} GdmSlaveProxyClass;
+
+GType gdm_slave_proxy_get_type (void);
+GdmSlaveProxy * gdm_slave_proxy_new (const char *display_id);
+gboolean gdm_slave_proxy_start (GdmSlaveProxy *slave);
+gboolean gdm_slave_proxy_stop (GdmSlaveProxy *slave);
+
+G_END_DECLS
+
+#endif /* __GDM_SLAVE_PROXY_H */
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
new file mode 100644
index 00000000..bf043383
--- /dev/null
+++ b/daemon/gdm-slave.c
@@ -0,0 +1,984 @@
+/* -*- 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-slave.h"
+#include "gdm-slave-glue.h"
+
+#include "gdm-server.h"
+#include "gdm-greeter.h"
+
+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"
+
+struct GdmSlavePrivate
+{
+ char *id;
+ GPid pid;
+ guint output_watch_id;
+ guint error_watch_id;
+
+ int ping_interval;
+
+ GPid server_pid;
+ Display *server_display;
+
+ /* cached display values */
+ char *display_id;
+ char *display_name;
+ int *display_number;
+ char *display_hostname;
+ gboolean display_is_local;
+ gboolean display_is_parented;
+ char *display_auth_file;
+ char *parent_display_name;
+ char *parent_display_auth_file;
+
+
+ GdmServer *server;
+ GdmGreeter *greeter;
+ DBusGProxy *display_proxy;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_ID,
+};
+
+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)
+
+/* adapted from gspawn.c */
+static int
+wait_on_child (int pid)
+{
+ int status;
+
+ wait_again:
+ if (waitpid (pid, &status, 0) < 0) {
+ if (errno == EINTR) {
+ goto wait_again;
+ } else if (errno == ECHILD) {
+ ; /* do nothing, child already reaped */
+ } else {
+ g_debug ("waitpid () should not fail in 'GdmSpawn'");
+ }
+ }
+
+ return status;
+}
+
+static void
+slave_died (GdmSlave *slave)
+{
+ int exit_status;
+
+ g_debug ("Waiting on process %d", slave->priv->pid);
+ exit_status = wait_on_child (slave->priv->pid);
+
+ if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
+ g_debug ("Wait on child process failed");
+ } else {
+ /* exited normally */
+ }
+
+ g_spawn_close_pid (slave->priv->pid);
+ slave->priv->pid = -1;
+
+ g_debug ("Slave died");
+}
+
+static gboolean
+output_watch (GIOChannel *source,
+ GIOCondition condition,
+ GdmSlave *slave)
+{
+ gboolean finished = FALSE;
+
+ if (condition & G_IO_IN) {
+ GIOStatus status;
+ GError *error = NULL;
+ char *line;
+
+ line = NULL;
+ status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
+
+ 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);
+ }
+ }
+ break;
+ case G_IO_STATUS_EOF:
+ finished = TRUE;
+ break;
+ case G_IO_STATUS_ERROR:
+ finished = TRUE;
+ g_debug ("Error reading from child: %s\n", error->message);
+ return FALSE;
+ case G_IO_STATUS_AGAIN:
+ default:
+ break;
+ }
+
+ g_free (line);
+ } else if (condition & G_IO_HUP) {
+ finished = TRUE;
+ }
+
+ if (finished) {
+ slave_died (slave);
+
+ slave->priv->output_watch_id = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* just for debugging */
+static gboolean
+error_watch (GIOChannel *source,
+ GIOCondition condition,
+ GdmSlave *slave)
+{
+ gboolean finished = FALSE;
+
+ if (condition & G_IO_IN) {
+ GIOStatus status;
+ GError *error = NULL;
+ char *line;
+
+ line = NULL;
+ status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
+
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ g_debug ("command error output: %s", line);
+ break;
+ case G_IO_STATUS_EOF:
+ finished = TRUE;
+ break;
+ case G_IO_STATUS_ERROR:
+ finished = TRUE;
+ g_debug ("Error reading from child: %s\n", error->message);
+ return FALSE;
+ case G_IO_STATUS_AGAIN:
+ default:
+ break;
+ }
+ g_free (line);
+ } else if (condition & G_IO_HUP) {
+ finished = TRUE;
+ }
+
+ if (finished) {
+ slave->priv->error_watch_id = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+spawn_slave (GdmSlave *slave)
+{
+ char *command;
+ char **argv;
+ gboolean result;
+ GIOChannel *channel;
+ GError *error = NULL;
+ int standard_output;
+ int standard_error;
+
+
+ result = FALSE;
+
+ command = g_strdup_printf ("%s --id %s", GDM_SLAVE_COMMAND, slave->priv->display_id);
+
+ if (! g_shell_parse_argv (command, NULL, &argv, &error)) {
+ g_warning ("Could not parse command: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ error = NULL;
+ result = g_spawn_async_with_pipes (NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &slave->priv->pid,
+ NULL,
+ &standard_output,
+ &standard_error,
+ &error);
+
+ if (! result) {
+ g_warning ("Could not start command '%s': %s", command, error->message);
+ g_error_free (error);
+ g_strfreev (argv);
+ goto out;
+ }
+
+ g_strfreev (argv);
+
+ /* output channel */
+ channel = g_io_channel_unix_new (standard_output);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+ g_io_channel_set_flags (channel,
+ g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
+ NULL);
+ slave->priv->output_watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc)output_watch,
+ slave);
+ g_io_channel_unref (channel);
+
+ /* error channel */
+ channel = g_io_channel_unix_new (standard_error);
+ g_io_channel_set_close_on_unref (channel, TRUE);
+ g_io_channel_set_flags (channel,
+ g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
+ NULL);
+ slave->priv->error_watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc)error_watch,
+ slave);
+ g_io_channel_unref (channel);
+
+ result = TRUE;
+
+ out:
+ g_free (command);
+
+ return result;
+}
+
+static int
+signal_pid (int pid,
+ int signal)
+{
+ int status = -1;
+
+ /* perhaps block sigchld */
+
+ status = kill (pid, signal);
+
+ if (status < 0) {
+ if (errno == ESRCH) {
+ g_warning ("Child process %lu was already dead.",
+ (unsigned long) pid);
+ } else {
+ g_warning ("Couldn't kill child process %lu: %s",
+ (unsigned long) pid,
+ g_strerror (errno));
+ }
+ }
+
+ /* perhaps unblock sigchld */
+
+ return status;
+}
+
+static void
+kill_slave (GdmSlave *slave)
+{
+ if (slave->priv->pid <= 1) {
+ return;
+ }
+
+ signal_pid (slave->priv->pid, SIGTERM);
+
+ /* watch should call slave_died */
+}
+
+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_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_script_environment (GdmSlave *slave,
+ const char *username)
+{
+ GPtrArray *env;
+ char **l;
+ 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);
+ for (l = environ; *l != NULL; l++) {
+ char **str;
+ str = g_strsplit (*l, "=", 2);
+ g_hash_table_insert (hash, str[0], str[1]);
+ }
+
+ /* 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_auth_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,
+ struct passwd *pwent,
+ gboolean pass_stdout)
+{
+ char *script;
+ char **argv;
+ gint status;
+ GError *error;
+ GPtrArray *env;
+ gboolean res;
+ gboolean ret;
+
+ 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;
+ }
+
+ 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 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);
+
+ 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);
+ }
+ }
+
+ /* We can use d->handled from now on on this display,
+ * since the lookup was done in server start */
+
+ g_setenv ("DISPLAY", slave->priv->display_name, TRUE);
+ g_unsetenv ("XAUTHORITY"); /* just in case it's set */
+
+#if 0
+ gdm_auth_set_local_auth (d);
+#endif
+
+#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
+
+ /* We keep our own (windowless) connection (dsp) open to avoid the
+ * X server resetting due to lack of active connections. */
+
+ g_debug ("gdm_slave_run: Opening display %s", slave->priv->display_name);
+
+ gdm_sigchld_block_push ();
+ slave->priv->server_display = XOpenDisplay (slave->priv->display_name);
+ gdm_sigchld_block_pop ();
+
+ if (slave->priv->server_display == NULL) {
+ return FALSE;
+ }
+
+
+ /* FIXME: handle wait for go */
+
+
+ /* 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",
+ NULL,
+ NULL,
+ FALSE /* pass_stdout */);
+
+ slave->priv->greeter = gdm_greeter_new (slave->priv->display_name);
+ gdm_greeter_start (slave->priv->greeter);
+
+ /* If XDMCP stop pinging */
+ if ( ! slave->priv->display_is_local) {
+ alarm (0);
+ }
+}
+
+gboolean
+gdm_slave_start (GdmSlave *slave)
+{
+ gboolean res;
+ char *id;
+ GError *error;
+
+ g_debug ("Starting 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);
+ if (slave->priv->display_proxy == NULL) {
+ g_warning ("Unable to create display proxy");
+ return FALSE;
+ }
+
+ /* Make sure display ID works */
+ error = NULL;
+ res = dbus_g_proxy_call (slave->priv->display_proxy,
+ "GetId",
+ &error,
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_OBJECT_PATH, &id,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to get display id %s: %s", slave->priv->display_id, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to get display id %s", slave->priv->display_id);
+ }
+
+ return FALSE;
+ }
+
+ g_debug ("Got display id: %s", id);
+
+ if (strcmp (id, slave->priv->display_id) != 0) {
+ g_critical ("Display ID doesn't match");
+ exit (1);
+ }
+
+ /* cache some values up front */
+ error = NULL;
+ res = dbus_g_proxy_call (slave->priv->display_proxy,
+ "IsLocal",
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &slave->priv->display_is_local,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to get value: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to get value");
+ }
+
+ return FALSE;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call (slave->priv->display_proxy,
+ "GetName",
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &slave->priv->display_name,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to get value: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to get value");
+ }
+
+ return FALSE;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call (slave->priv->display_proxy,
+ "GetNumber",
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &slave->priv->display_number,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to get value: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to get value");
+ }
+
+ return FALSE;
+ }
+
+ gdm_slave_run (slave);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_slave_stop (GdmSlave *slave)
+{
+ g_debug ("Stopping slave");
+
+ if (slave->priv->display_proxy != NULL) {
+ g_object_unref (slave->priv->display_proxy);
+ }
+
+ return TRUE;
+}
+
+static void
+_gdm_slave_set_display_id (GdmSlave *slave,
+ const char *id)
+{
+ g_free (slave->priv->display_id);
+ slave->priv->display_id = g_strdup (id);
+}
+
+static void
+gdm_slave_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSlave *self;
+
+ self = GDM_SLAVE (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_ID:
+ _gdm_slave_set_display_id (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_slave_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmSlave *self;
+
+ self = GDM_SLAVE (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY_ID:
+ g_value_set_string (value, self->priv->display_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+register_slave (GdmSlave *slave)
+{
+ GError *error = NULL;
+
+ error = NULL;
+ slave->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (slave->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+
+ dbus_g_connection_register_g_object (slave->priv->connection, slave->priv->id, G_OBJECT (slave));
+
+ return TRUE;
+}
+
+
+static GObject *
+gdm_slave_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmSlave *slave;
+ GdmSlaveClass *klass;
+ gboolean res;
+ const char *id;
+
+ klass = GDM_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_SLAVE));
+
+ slave = GDM_SLAVE (G_OBJECT_CLASS (gdm_slave_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ id = NULL;
+ if (g_str_has_prefix (slave->priv->display_id, "/org/gnome/DisplayManager/Display")) {
+ id = slave->priv->display_id + strlen ("/org/gnome/DisplayManager/Display");
+ }
+
+ slave->priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Slave%s", id);
+ g_debug ("Registering %s", slave->priv->id);
+
+ res = register_slave (slave);
+ if (! res) {
+ g_warning ("Unable to register slave with system bus");
+ }
+
+ return G_OBJECT (slave);
+}
+
+static void
+gdm_slave_class_init (GdmSlaveClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_slave_get_property;
+ object_class->set_property = gdm_slave_set_property;
+ object_class->constructor = gdm_slave_constructor;
+ object_class->finalize = gdm_slave_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmSlavePrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_ID,
+ g_param_spec_string ("display-id",
+ "id",
+ "id",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ dbus_g_object_type_install_info (GDM_TYPE_SLAVE, &dbus_glib_gdm_slave_object_info);
+}
+
+static void
+gdm_slave_init (GdmSlave *slave)
+{
+
+ slave->priv = GDM_SLAVE_GET_PRIVATE (slave);
+
+ slave->priv->pid = -1;
+}
+
+static void
+gdm_slave_finalize (GObject *object)
+{
+ GdmSlave *slave;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_SLAVE (object));
+
+ slave = GDM_SLAVE (object);
+
+ g_return_if_fail (slave->priv != NULL);
+
+ 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
new file mode 100644
index 00000000..ffc198ae
--- /dev/null
+++ b/daemon/gdm-slave.h
@@ -0,0 +1,56 @@
+/* -*- 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_SLAVE_H
+#define __GDM_SLAVE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SLAVE (gdm_slave_get_type ())
+#define GDM_SLAVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SLAVE, GdmSlave))
+#define GDM_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SLAVE, GdmSlaveClass))
+#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_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SLAVE, GdmSlaveClass))
+
+typedef struct GdmSlavePrivate GdmSlavePrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmSlavePrivate *priv;
+} GdmSlave;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+} GdmSlaveClass;
+
+GType gdm_slave_get_type (void);
+GdmSlave * gdm_slave_new (const char *display_id);
+gboolean gdm_slave_start (GdmSlave *slave);
+
+G_END_DECLS
+
+#endif /* __GDM_SLAVE_H */
diff --git a/daemon/gdm-slave.xml b/daemon/gdm-slave.xml
new file mode 100644
index 00000000..65665949
--- /dev/null
+++ b/daemon/gdm-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.Slave">
+ </interface>
+</node>
diff --git a/daemon/gdm-static-display.c b/daemon/gdm-static-display.c
new file mode 100644
index 00000000..f02f40c4
--- /dev/null
+++ b/daemon/gdm-static-display.c
@@ -0,0 +1,175 @@
+/* -*- 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 <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-display.h"
+#include "gdm-static-display.h"
+#include "gdm-static-display-glue.h"
+
+#define GDM_STATIC_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_STATIC_DISPLAY, GdmStaticDisplayPrivate))
+
+struct GdmStaticDisplayPrivate
+{
+ struct sockaddr_storage addr;
+};
+
+enum {
+ PROP_0,
+};
+
+static void gdm_static_display_class_init (GdmStaticDisplayClass *klass);
+static void gdm_static_display_init (GdmStaticDisplay *static_display);
+static void gdm_static_display_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmStaticDisplay, gdm_static_display, GDM_TYPE_DISPLAY)
+
+static gboolean
+gdm_static_display_create_authority (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ GDM_DISPLAY_CLASS (gdm_static_display_parent_class)->create_authority (display);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_static_display_manage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ GDM_DISPLAY_CLASS (gdm_static_display_parent_class)->manage (display);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_static_display_unmanage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ GDM_DISPLAY_CLASS (gdm_static_display_parent_class)->unmanage (display);
+
+ return TRUE;
+}
+
+static void
+gdm_static_display_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmStaticDisplay *self;
+
+ self = GDM_STATIC_DISPLAY (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_static_display_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmStaticDisplay *self;
+
+ self = GDM_STATIC_DISPLAY (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_static_display_class_init (GdmStaticDisplayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
+
+ object_class->get_property = gdm_static_display_get_property;
+ object_class->set_property = gdm_static_display_set_property;
+ object_class->finalize = gdm_static_display_finalize;
+
+ display_class->create_authority = gdm_static_display_create_authority;
+ display_class->manage = gdm_static_display_manage;
+ display_class->unmanage = gdm_static_display_unmanage;
+
+ g_type_class_add_private (klass, sizeof (GdmStaticDisplayPrivate));
+
+ dbus_g_object_type_install_info (GDM_TYPE_STATIC_DISPLAY, &dbus_glib_gdm_static_display_object_info);
+}
+
+static void
+gdm_static_display_init (GdmStaticDisplay *static_display)
+{
+
+ static_display->priv = GDM_STATIC_DISPLAY_GET_PRIVATE (static_display);
+}
+
+static void
+gdm_static_display_finalize (GObject *object)
+{
+ GdmStaticDisplay *static_display;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_STATIC_DISPLAY (object));
+
+ static_display = GDM_STATIC_DISPLAY (object);
+
+ g_return_if_fail (static_display->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_static_display_parent_class)->finalize (object);
+}
+
+GdmDisplay *
+gdm_static_display_new (int number,
+ const char *name)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_STATIC_DISPLAY,
+ "number", number,
+ "name", name,
+ NULL);
+
+ return GDM_DISPLAY (object);
+}
diff --git a/daemon/gdm-static-display.h b/daemon/gdm-static-display.h
new file mode 100644
index 00000000..30b94fcd
--- /dev/null
+++ b/daemon/gdm-static-display.h
@@ -0,0 +1,61 @@
+/* -*- 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_STATIC_DISPLAY_H
+#define __GDM_STATIC_DISPLAY_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include "gdm-display.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_STATIC_DISPLAY (gdm_static_display_get_type ())
+#define GDM_STATIC_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_STATIC_DISPLAY, GdmStaticDisplay))
+#define GDM_STATIC_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_STATIC_DISPLAY, GdmStaticDisplayClass))
+#define GDM_IS_STATIC_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_STATIC_DISPLAY))
+#define GDM_IS_STATIC_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_STATIC_DISPLAY))
+#define GDM_STATIC_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_STATIC_DISPLAY, GdmStaticDisplayClass))
+
+typedef struct GdmStaticDisplayPrivate GdmStaticDisplayPrivate;
+
+typedef struct
+{
+ GdmDisplay parent;
+ GdmStaticDisplayPrivate *priv;
+} GdmStaticDisplay;
+
+typedef struct
+{
+ GdmDisplayClass parent_class;
+
+} GdmStaticDisplayClass;
+
+GType gdm_static_display_get_type (void);
+GdmDisplay * gdm_static_display_new (int number,
+ const char *name);
+
+
+G_END_DECLS
+
+#endif /* __GDM_STATIC_DISPLAY_H */
diff --git a/daemon/gdm-static-display.xml b/daemon/gdm-static-display.xml
new file mode 100644
index 00000000..bd3670b8
--- /dev/null
+++ b/daemon/gdm-static-display.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.StaticDisplay">
+ </interface>
+</node>
diff --git a/daemon/gdm-xdmcp-display.c b/daemon/gdm-xdmcp-display.c
new file mode 100644
index 00000000..df2342a9
--- /dev/null
+++ b/daemon/gdm-xdmcp-display.c
@@ -0,0 +1,329 @@
+/* -*- 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 <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-display.h"
+#include "gdm-xdmcp-display.h"
+#include "gdm-xdmcp-display-glue.h"
+
+#include "gdm-common.h"
+#include "gdm-address.h"
+
+#include "cookie.h"
+#include "auth.h"
+
+#define GDM_XDMCP_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_DISPLAY, GdmXdmcpDisplayPrivate))
+
+struct GdmXdmcpDisplayPrivate
+{
+ char *remote_hostname;
+ GdmAddress *remote_address;
+ gint32 session_number;
+};
+
+enum {
+ PROP_0,
+ PROP_REMOTE_HOSTNAME,
+ PROP_REMOTE_ADDRESS,
+ PROP_SESSION_NUMBER,
+};
+
+static void gdm_xdmcp_display_class_init (GdmXdmcpDisplayClass *klass);
+static void gdm_xdmcp_display_init (GdmXdmcpDisplay *xdmcp_display);
+static void gdm_xdmcp_display_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmXdmcpDisplay, gdm_xdmcp_display, GDM_TYPE_DISPLAY)
+
+gint32
+gdm_xdmcp_display_get_session_number (GdmXdmcpDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY (display), 0);
+
+ return display->priv->session_number;
+}
+
+gboolean
+gdm_xdmcp_display_get_remote_hostname (GdmXdmcpDisplay *display,
+ char **hostname,
+ GError **error)
+{
+ g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY (display), FALSE);
+
+ if (hostname != NULL) {
+ *hostname = g_strdup (display->priv->remote_hostname);
+ }
+
+ return TRUE;
+}
+
+GdmAddress *
+gdm_xdmcp_display_get_remote_address (GdmXdmcpDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY (display), NULL);
+
+ return display->priv->remote_address;
+}
+
+static gboolean
+gdm_xdmcp_display_create_authority (GdmDisplay *display)
+{
+ FILE *af;
+ int closeret;
+ gboolean ret;
+ char *authfile;
+ int display_num;
+ char *name;
+ char *cookie;
+ char *bcookie;
+ GSList *authlist;
+ char *basename;
+
+ ret = FALSE;
+ name = NULL;
+
+ g_object_get (display,
+ "name", &name,
+ "number", &display_num,
+ NULL);
+
+ g_debug ("Setting up access for %s", name);
+
+ /* gdm and xserver authfile can be the same, server will run as root */
+ basename = g_strconcat (name, ".Xauth", NULL);
+ authfile = g_build_filename (AUTHDIR, basename, NULL);
+ g_free (basename);
+
+ af = gdm_safe_fopen_w (authfile, 0644);
+ if (af == NULL) {
+ g_warning (_("Cannot safely open %s"), authfile);
+ g_free (authfile);
+ goto out;
+ }
+
+ /* Create new random cookie */
+ gdm_cookie_generate (&cookie, &bcookie);
+ authlist = NULL;
+ if (! gdm_auth_add_entry_for_display (display_num, bcookie, &authlist, af)) {
+ goto out;
+ }
+
+ g_debug ("gdm_auth_secure_display: Setting up access");
+
+ VE_IGNORE_EINTR (closeret = fclose (af));
+ if (closeret < 0) {
+ g_warning (_("Could not write new authorization entry: %s"),
+ g_strerror (errno));
+ goto out;
+ }
+
+ g_debug ("Set up access for %s - %d entries",
+ name,
+ g_slist_length (authlist));
+
+ /* FIXME: save authlist */
+
+ g_object_set (display,
+ "authority-file", authfile,
+ "cookie", cookie,
+ "binary-cookie", bcookie,
+ NULL);
+
+ ret = TRUE;
+
+ out:
+ g_free (name);
+
+ return ret;
+}
+
+static gboolean
+gdm_xdmcp_display_manage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ GDM_DISPLAY_CLASS (gdm_xdmcp_display_parent_class)->manage (display);
+
+ return TRUE;
+}
+
+static gboolean
+gdm_xdmcp_display_unmanage (GdmDisplay *display)
+{
+ g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+ GDM_DISPLAY_CLASS (gdm_xdmcp_display_parent_class)->unmanage (display);
+
+ return TRUE;
+}
+
+static void
+gdm_xdmcp_display_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmXdmcpDisplay *self;
+
+ self = GDM_XDMCP_DISPLAY (object);
+
+ switch (prop_id) {
+ case PROP_REMOTE_HOSTNAME:
+ self->priv->remote_hostname = g_value_dup_string (value);
+ break;
+ case PROP_REMOTE_ADDRESS:
+ self->priv->remote_address = g_value_get_boxed (value);
+ break;
+ case PROP_SESSION_NUMBER:
+ self->priv->session_number = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_xdmcp_display_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmXdmcpDisplay *self;
+
+ self = GDM_XDMCP_DISPLAY (object);
+
+ switch (prop_id) {
+ case PROP_REMOTE_HOSTNAME:
+ g_value_set_string (value, self->priv->remote_hostname);
+ break;
+ case PROP_REMOTE_ADDRESS:
+ g_value_set_boxed (value, self->priv->remote_address);
+ break;
+ case PROP_SESSION_NUMBER:
+ g_value_set_int (value, self->priv->session_number);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_xdmcp_display_class_init (GdmXdmcpDisplayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
+
+ object_class->get_property = gdm_xdmcp_display_get_property;
+ object_class->set_property = gdm_xdmcp_display_set_property;
+ object_class->finalize = gdm_xdmcp_display_finalize;
+
+ display_class->create_authority = gdm_xdmcp_display_create_authority;
+ display_class->manage = gdm_xdmcp_display_manage;
+ display_class->unmanage = gdm_xdmcp_display_unmanage;
+
+ g_type_class_add_private (klass, sizeof (GdmXdmcpDisplayPrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_REMOTE_HOSTNAME,
+ g_param_spec_string ("remote-hostname",
+ "remote-hostname",
+ "remote-hostname",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_REMOTE_ADDRESS,
+ g_param_spec_boxed ("remote-address",
+ "Remote address",
+ "Remote address",
+ GDM_TYPE_ADDRESS,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_SESSION_NUMBER,
+ g_param_spec_int ("session-number",
+ "session-number",
+ "session-number",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ dbus_g_object_type_install_info (GDM_TYPE_XDMCP_DISPLAY, &dbus_glib_gdm_xdmcp_display_object_info);
+}
+
+static void
+gdm_xdmcp_display_init (GdmXdmcpDisplay *xdmcp_display)
+{
+
+ xdmcp_display->priv = GDM_XDMCP_DISPLAY_GET_PRIVATE (xdmcp_display);
+}
+
+static void
+gdm_xdmcp_display_finalize (GObject *object)
+{
+ GdmXdmcpDisplay *xdmcp_display;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_XDMCP_DISPLAY (object));
+
+ xdmcp_display = GDM_XDMCP_DISPLAY (object);
+
+ g_return_if_fail (xdmcp_display->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_xdmcp_display_parent_class)->finalize (object);
+}
+
+GdmDisplay *
+gdm_xdmcp_display_new (int number,
+ const char *name,
+ const char *hostname,
+ GdmAddress *address,
+ gint32 session_number)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_XDMCP_DISPLAY,
+ "is-local", FALSE,
+ "number", number,
+ "name", name,
+ "remote-hostname", hostname,
+ "remote-address", address,
+ "session-number", session_number,
+ NULL);
+
+ return GDM_DISPLAY (object);
+}
diff --git a/daemon/gdm-xdmcp-display.h b/daemon/gdm-xdmcp-display.h
new file mode 100644
index 00000000..3a132588
--- /dev/null
+++ b/daemon/gdm-xdmcp-display.h
@@ -0,0 +1,77 @@
+/* -*- 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_XDMCP_DISPLAY_H
+#define __GDM_XDMCP_DISPLAY_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "gdm-display.h"
+#include "gdm-address.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_XDMCP_DISPLAY (gdm_xdmcp_display_get_type ())
+#define GDM_XDMCP_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_DISPLAY, GdmXdmcpDisplay))
+#define GDM_XDMCP_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_DISPLAY, GdmXdmcpDisplayClass))
+#define GDM_IS_XDMCP_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_DISPLAY))
+#define GDM_IS_XDMCP_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_DISPLAY))
+#define GDM_XDMCP_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_DISPLAY, GdmXdmcpDisplayClass))
+
+typedef struct GdmXdmcpDisplayPrivate GdmXdmcpDisplayPrivate;
+
+typedef struct
+{
+ GdmDisplay parent;
+ GdmXdmcpDisplayPrivate *priv;
+} GdmXdmcpDisplay;
+
+typedef struct
+{
+ GdmDisplayClass parent_class;
+
+} GdmXdmcpDisplayClass;
+
+GType gdm_xdmcp_display_get_type (void);
+
+
+GdmDisplay * gdm_xdmcp_display_new (int number,
+ const char *name,
+ const char *hostname,
+ GdmAddress *addr,
+ gint32 serial_number);
+
+gint32 gdm_xdmcp_display_get_session_number (GdmXdmcpDisplay *display);
+GdmAddress * gdm_xdmcp_display_get_remote_address (GdmXdmcpDisplay *display);
+
+
+/* exported */
+gboolean gdm_xdmcp_display_get_remote_hostname (GdmXdmcpDisplay *display,
+ char **hostname,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* __GDM_XDMCP_DISPLAY_H */
diff --git a/daemon/gdm-xdmcp-display.xml b/daemon/gdm-xdmcp-display.xml
new file mode 100644
index 00000000..512019ce
--- /dev/null
+++ b/daemon/gdm-xdmcp-display.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.XdmcpDisplay">
+ </interface>
+</node>
diff --git a/daemon/gdm-xdmcp-manager.c b/daemon/gdm-xdmcp-manager.c
index ad377024..297dfc89 100644
--- a/daemon/gdm-xdmcp-manager.c
+++ b/daemon/gdm-xdmcp-manager.c
@@ -51,13 +51,15 @@
#include <X11/Xdmcp.h>
#include "gdm-common.h"
+#include "gdm-xdmcp-display.h"
#include "gdm-xdmcp-manager.h"
+#include "gdm-display-store.h"
-#include "misc.h"
#include "auth.h"
#include "cookie.h"
#include "choose.h"
-#include "gdm-daemon-config.h"
+#include "gdm-master-config.h"
+#include "gdm-daemon-config-entries.h"
/*
* On Sun, we need to define allow_severity and deny_severity to link
@@ -138,21 +140,23 @@ static XdmAuthRec serv_authlist = {
/* NOTE: Timeout and max are hardcoded */
typedef struct _GdmForwardQuery {
- time_t acctime;
- struct sockaddr_storage *dsp_sa;
- struct sockaddr_storage *from_sa;
+ time_t acctime;
+ GdmAddress *dsp_address;
+ GdmAddress *from_address;
} GdmForwardQuery;
typedef struct {
- int times;
- guint handler;
- struct sockaddr_storage manager;
- struct sockaddr_storage origin;
- GdmXdmcpManager *xdmcp_manager;
+ int times;
+ guint handler;
+ GdmAddress *manager;
+ GdmAddress *origin;
+ GdmXdmcpManager *xdmcp_manager;
} ManagedForward;
struct GdmXdmcpManagerPrivate
{
+ GdmDisplayStore *display_store;
+
GSList *forward_queries;
GSList *managed_forwards;
@@ -188,6 +192,7 @@ enum {
enum {
PROP_0,
+ PROP_DISPLAY_STORE,
PROP_PORT,
PROP_USE_MULTICAST,
PROP_MULTICAST_ADDRESS,
@@ -449,13 +454,17 @@ do_bind (guint port,
debug_addrinfo (ai);
if (sock < 0) {
- char *host;
- char *serv;
+ char *host;
+ char *serv;
+ GdmAddress *addr;
- gdm_address_get_info ((struct sockaddr_storage *)ai->ai_addr, &host, &serv);
+ addr = gdm_address_new_from_sockaddr_storage ((struct sockaddr_storage *)ai->ai_addr);
+ gdm_address_get_numeric_info (addr, &host, &serv);
g_debug ("XDMCP: Attempting to bind to host %s port %s", host, serv);
g_free (host);
g_free (serv);
+ gdm_address_free (addr);
+
sock = create_socket (ai);
if (sock >= 0) {
if (hostaddr != NULL) {
@@ -568,6 +577,8 @@ open_port (GdmXdmcpManager *manager)
return FALSE;
}
+ gdm_fd_set_close_on_exec (manager->priv->socket_fd);
+
if (manager->priv->use_multicast) {
setup_multicast (manager);
}
@@ -576,7 +587,7 @@ open_port (GdmXdmcpManager *manager)
}
static gboolean
-gdm_xdmcp_host_allow (struct sockaddr_storage *clnt_sa)
+gdm_xdmcp_host_allow (GdmAddress *address)
{
#ifdef HAVE_TCPWRAPPERS
@@ -589,29 +600,21 @@ gdm_xdmcp_host_allow (struct sockaddr_storage *clnt_sa)
char *client_addr,
char *client_user);
- GdmHostent *client_he;
char *client;
- gboolean ret;
char *host;
+ gboolean ret;
- /* Find client hostname */
- client_he = gdm_gethostbyaddr (clnt_sa);
+ host = NULL;
- if (client_he->not_found) {
- client = "unknown";
- } else {
- g_debug ("gdm_xdmcp_host_allow: client->hostname is %s\n",
- client_he->hostname);
- client = client_he->hostname;
- }
+ /* Find client hostname */
+ client = gdm_address_get_hostname (address);
+ gdm_address_get_numeric_info (address, &host, NULL);
/* Check with tcp_wrappers if client is allowed to access */
- host = NULL;
- gdm_address_get_info (clnt_sa, &host, NULL);
ret = hosts_ctl ("gdm", client, host, "");
- g_free (host);
- gdm_hostent_free (client_he);
+ g_free (host);
+ g_free (client);
return ret;
#else /* HAVE_TCPWRAPPERS */
@@ -619,49 +622,91 @@ gdm_xdmcp_host_allow (struct sockaddr_storage *clnt_sa)
#endif /* HAVE_TCPWRAPPERS */
}
-static int
-gdm_xdmcp_num_displays_from_host (GdmXdmcpManager *manager,
- struct sockaddr_storage *addr)
+typedef struct {
+ GdmAddress *address;
+ int count;
+} CountDisplayData;
+
+static gboolean
+count_displays_from_host (const char *id,
+ GdmDisplay *display,
+ CountDisplayData *data)
{
- GSList *li;
- int count = 0;
- GSList *displays;
+ GdmAddress *address;
- displays = gdm_daemon_config_get_display_list ();
+ if (GDM_IS_XDMCP_DISPLAY (display)) {
+ address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (SERVER_IS_XDMCP (disp)) {
- if (gdm_address_equal (&disp->addr, addr)) {
- count++;
- }
+ if (gdm_address_equal (address, data->address)) {
+ data->count++;
}
}
- return count;
+
+ return TRUE;
}
-static GdmDisplay *
-gdm_xdmcp_display_lookup_by_host (GdmXdmcpManager *manager,
- struct sockaddr_storage *addr,
- int dspnum)
+static int
+gdm_xdmcp_num_displays_from_host (GdmXdmcpManager *manager,
+ GdmAddress *address)
{
- GSList *li;
- GSList *displays;
+ CountDisplayData data;
- displays = gdm_daemon_config_get_display_list ();
+ data.count = 0;
+ data.address = address;
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (SERVER_IS_XDMCP (disp)) {
+ gdm_display_store_foreach (manager->priv->display_store,
+ (GdmDisplayStoreFunc)count_displays_from_host,
+ &data);
- if (gdm_address_equal (&disp->addr, addr)
- && disp->xdmcp_dispnum == dspnum) {
- return disp;
- }
- }
+ return data.count;
+}
+
+typedef struct {
+ GdmAddress *address;
+ int display_num;
+} LookupHostData;
+
+static gboolean
+lookup_by_host (const char *id,
+ GdmDisplay *display,
+ LookupHostData *data)
+{
+ GdmAddress *this_address;
+ int disp_num;
+
+ if (! GDM_IS_XDMCP_DISPLAY (display)) {
+ return FALSE;
+ }
+
+ this_address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
+ gdm_display_get_number (display, &disp_num, NULL);
+
+ if (gdm_address_equal (this_address, data->address)
+ && disp_num == data->display_num) {
+ return TRUE;
}
- return NULL;
+ return FALSE;
+}
+
+static GdmDisplay *
+gdm_xdmcp_display_lookup_by_host (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int display_num)
+{
+ GdmDisplay *display;
+ LookupHostData *data;
+
+ data = g_new0 (LookupHostData, 1);
+ data->address = address;
+ data->display_num = display_num;
+
+ display = gdm_display_store_find (manager->priv->display_store,
+ (GdmDisplayStoreFunc)lookup_by_host,
+ data);
+ g_free (data);
+
+ return display;
}
static char *
@@ -709,8 +754,8 @@ get_willing_output (GdmXdmcpManager *manager)
}
static void
-gdm_xdmcp_send_willing (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa)
+gdm_xdmcp_send_willing (GdmXdmcpManager *manager,
+ GdmAddress *address)
{
ARRAY8 status;
XdmcpHeader header;
@@ -718,7 +763,7 @@ gdm_xdmcp_send_willing (GdmXdmcpManager *manager,
static time_t last_willing = 0;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Sending WILLING to %s", host);
g_free (host);
@@ -736,8 +781,8 @@ gdm_xdmcp_send_willing (GdmXdmcpManager *manager,
}
}
- if (! gdm_address_is_local (clnt_sa) &&
- gdm_xdmcp_num_displays_from_host (manager, clnt_sa) >= manager->priv->max_displays_per_host) {
+ if (! gdm_address_is_local (address) &&
+ gdm_xdmcp_num_displays_from_host (manager, address) >= manager->priv->max_displays_per_host) {
/*
* Don't translate, this goes over the wire to servers where we
* don't know the charset or language, so it must be ascii
@@ -763,16 +808,16 @@ gdm_xdmcp_send_willing (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
g_free (status.data);
}
static void
-gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int type)
+gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int type)
{
ARRAY8 status;
XdmcpHeader header;
@@ -785,7 +830,7 @@ gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager,
return;
}
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Sending UNWILLING to %s", host);
g_warning (_("Denied XDMCP query from host %s"), host);
g_free (host);
@@ -806,7 +851,7 @@ gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager,
XdmcpWriteARRAY8 (&manager->priv->buf, &status);
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
last_time = time (NULL);
@@ -816,9 +861,13 @@ gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager,
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
static void
-set_port_for_request (struct sockaddr_storage *ss,
- ARRAY8 *port)
+set_port_for_request (GdmAddress *address,
+ ARRAY8 *port)
{
+ struct sockaddr_storage *ss;
+
+ ss = gdm_address_peek_sockaddr_storage (address);
+
/* we depend on this being 2 elsewhere as well */
port->length = 2;
@@ -836,22 +885,25 @@ set_port_for_request (struct sockaddr_storage *ss,
}
static void
-set_address_for_request (struct sockaddr_storage *ss,
- ARRAY8 *address)
+set_address_for_request (GdmAddress *address,
+ ARRAY8 *addr)
{
+ struct sockaddr_storage *ss;
+
+ ss = gdm_address_peek_sockaddr_storage (address);
switch (ss->ss_family) {
case AF_INET:
- address->length = sizeof (struct in_addr);
- address->data = g_memdup (&SIN (ss)->sin_addr, address->length);
+ addr->length = sizeof (struct in_addr);
+ addr->data = g_memdup (&SIN (ss)->sin_addr, addr->length);
break;
case AF_INET6:
- address->length = sizeof (struct in6_addr);
- address->data = g_memdup (&SIN6 (ss)->sin6_addr, address->length);
+ addr->length = sizeof (struct in6_addr);
+ addr->data = g_memdup (&SIN6 (ss)->sin6_addr, addr->length);
break;
default:
- address->length = 0;
- address->data = NULL;
+ addr->length = 0;
+ addr->data = NULL;
break;
}
@@ -860,14 +912,13 @@ set_address_for_request (struct sockaddr_storage *ss,
static void
gdm_xdmcp_send_forward_query (GdmXdmcpManager *manager,
GdmIndirectDisplay *id,
- struct sockaddr_storage *clnt_sa,
- struct sockaddr_storage *display_addr,
+ GdmAddress *address,
+ GdmAddress *display_address,
ARRAYofARRAY8Ptr authlist)
{
- struct sockaddr_storage *sa;
XdmcpHeader header;
int i;
- ARRAY8 address;
+ ARRAY8 addr;
ARRAY8 port;
char *host;
char *serv;
@@ -875,26 +926,24 @@ gdm_xdmcp_send_forward_query (GdmXdmcpManager *manager,
g_assert (id != NULL);
g_assert (id->chosen_host != NULL);
- gdm_address_get_info (id->chosen_host, &host, NULL);
+ gdm_address_get_numeric_info (id->chosen_host, &host, NULL);
g_debug ("XDMCP: Sending forward query to %s",
host);
g_free (host);
- gdm_address_get_info (display_addr, &host, &serv);
+ gdm_address_get_numeric_info (display_address, &host, &serv);
g_debug ("gdm_xdmcp_send_forward_query: Query contains %s:%s",
host, serv);
g_free (host);
g_free (serv);
- set_port_for_request (clnt_sa, &port);
- set_address_for_request (display_addr, &address);
-
- sa = g_memdup (id->chosen_host, sizeof (id->chosen_host));
+ set_port_for_request (address, &port);
+ set_address_for_request (display_address, &addr);
header.version = XDM_PROTOCOL_VERSION;
header.opcode = (CARD16) FORWARD_QUERY;
header.length = 0;
- header.length += 2 + address.length;
+ header.length += 2 + addr.length;
header.length += 2 + port.length;
header.length += 1;
for (i = 0; i < authlist->length; i++) {
@@ -902,32 +951,31 @@ gdm_xdmcp_send_forward_query (GdmXdmcpManager *manager,
}
XdmcpWriteHeader (&manager->priv->buf, &header);
- XdmcpWriteARRAY8 (&manager->priv->buf, &address);
+ XdmcpWriteARRAY8 (&manager->priv->buf, &addr);
XdmcpWriteARRAY8 (&manager->priv->buf, &port);
XdmcpWriteARRAYofARRAY8 (&manager->priv->buf, authlist);
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr) sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (id->chosen_host),
(int)sizeof (struct sockaddr_storage));
g_free (port.data);
- g_free (address.data);
- g_free (sa);
+ g_free (addr.data);
}
static void
handle_any_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
+ GdmAddress *address,
ARRAYofARRAY8Ptr authentication_names,
int type)
{
- gdm_xdmcp_send_willing (manager, clnt_sa);
+ gdm_xdmcp_send_willing (manager, address);
}
static void
handle_direct_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
+ GdmAddress *address,
int len,
int type)
{
@@ -949,7 +997,7 @@ handle_direct_query (GdmXdmcpManager *manager,
}
if (len == expected_len) {
- handle_any_query (manager, clnt_sa, &clnt_authlist, type);
+ handle_any_query (manager, address, &clnt_authlist, type);
} else {
g_warning (_("Error in checksum"));
}
@@ -958,40 +1006,41 @@ handle_direct_query (GdmXdmcpManager *manager,
}
static void
-gdm_xdmcp_handle_broadcast_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_broadcast_query (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
- if (gdm_xdmcp_host_allow (clnt_sa)) {
- handle_direct_query (manager, clnt_sa, len, BROADCAST_QUERY);
+ if (gdm_xdmcp_host_allow (address)) {
+ handle_direct_query (manager, address, len, BROADCAST_QUERY);
} else {
/* just ignore it */
}
}
static void
-gdm_xdmcp_handle_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_query (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
- if (gdm_xdmcp_host_allow (clnt_sa)) {
- handle_direct_query (manager, clnt_sa, len, QUERY);
+ if (gdm_xdmcp_host_allow (address)) {
+ handle_direct_query (manager, address, len, QUERY);
} else {
- gdm_xdmcp_send_unwilling (manager, clnt_sa, QUERY);
+ gdm_xdmcp_send_unwilling (manager, address, QUERY);
}
}
static void
-gdm_xdmcp_handle_indirect_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
-{
- ARRAYofARRAY8 clnt_authlist;
- int expected_len;
- int i;
- int res;
+gdm_xdmcp_handle_indirect_query (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
+{
+ ARRAYofARRAY8 clnt_authlist;
+ int expected_len;
+ int i;
+ int res;
+ GdmIndirectDisplay *id;
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
/* ignore the request */
return;
}
@@ -1017,59 +1066,59 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpManager *manager,
* the pending list. If found send a FORWARD_QUERY to the
* chosen manager. Otherwise alloc a new indirect display. */
- if (len == expected_len) {
- GdmIndirectDisplay *id;
-
- id = gdm_choose_indirect_lookup (clnt_sa);
-
- if (id != NULL && id->chosen_host != NULL) {
- /* if user chose us, then just send willing */
- if (gdm_address_is_local (id->chosen_host)) {
- /* get rid of indirect, so that we don't get
- * the chooser */
- gdm_choose_indirect_dispose (id);
- gdm_xdmcp_send_willing (manager, clnt_sa);
- } else if (gdm_address_is_loopback (clnt_sa)) {
- /* woohoo! fun, I have no clue how to get
- * the correct ip, SO I just send forward
- * queries with all the different IPs */
- const GList *list = gdm_address_peek_local_list ();
-
- while (list != NULL) {
- struct sockaddr_storage *saddr = list->data;
-
- if (! gdm_address_is_loopback (saddr)) {
- /* forward query to * chosen host */
- gdm_xdmcp_send_forward_query (manager,
- id,
- clnt_sa,
- saddr,
- &clnt_authlist);
- }
-
- list = list->next;
+ if (len != expected_len) {
+ g_warning (_("Error in checksum"));
+ goto out;
+ }
+
+
+ id = gdm_choose_indirect_lookup (address);
+
+ if (id != NULL && id->chosen_host != NULL) {
+ /* if user chose us, then just send willing */
+ if (gdm_address_is_local (id->chosen_host)) {
+ /* get rid of indirect, so that we don't get
+ * the chooser */
+ gdm_choose_indirect_dispose (id);
+ gdm_xdmcp_send_willing (manager, address);
+ } else if (gdm_address_is_loopback (address)) {
+ /* woohoo! fun, I have no clue how to get
+ * the correct ip, SO I just send forward
+ * queries with all the different IPs */
+ const GList *list = gdm_address_peek_local_list ();
+
+ while (list != NULL) {
+ GdmAddress *saddr = list->data;
+
+ if (! gdm_address_is_loopback (saddr)) {
+ /* forward query to * chosen host */
+ gdm_xdmcp_send_forward_query (manager,
+ id,
+ address,
+ saddr,
+ &clnt_authlist);
}
- } else {
- /* or send forward query to chosen host */
- gdm_xdmcp_send_forward_query (manager,
- id,
- clnt_sa,
- clnt_sa,
- &clnt_authlist);
- }
- } else if (id == NULL) {
- id = gdm_choose_indirect_alloc (clnt_sa);
- if (id != NULL) {
- gdm_xdmcp_send_willing (manager, clnt_sa);
+
+ list = list->next;
}
- } else {
- gdm_xdmcp_send_willing (manager, clnt_sa);
+ } else {
+ /* or send forward query to chosen host */
+ gdm_xdmcp_send_forward_query (manager,
+ id,
+ address,
+ address,
+ &clnt_authlist);
}
-
- } else {
- g_warning (_("Error in checksum"));
+ } else if (id == NULL) {
+ id = gdm_choose_indirect_alloc (address);
+ if (id != NULL) {
+ gdm_xdmcp_send_willing (manager, address);
+ }
+ } else {
+ gdm_xdmcp_send_willing (manager, address);
}
+out:
XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
}
@@ -1088,15 +1137,15 @@ gdm_forward_query_dispose (GdmXdmcpManager *manager,
{
char *host;
- gdm_address_get_info (q->dsp_sa, &host, NULL);
+ gdm_address_get_numeric_info (q->dsp_address, &host, NULL);
g_debug ("gdm_forward_query_dispose: Disposing %s", host);
g_free (host);
}
- g_free (q->dsp_sa);
- q->dsp_sa = NULL;
- g_free (q->from_sa);
- q->from_sa = NULL;
+ g_free (q->dsp_address);
+ q->dsp_address = NULL;
+ g_free (q->from_address);
+ q->from_address = NULL;
g_free (q);
}
@@ -1124,9 +1173,9 @@ remove_oldest_forward (GdmXdmcpManager *manager)
}
static GdmForwardQuery *
-gdm_forward_query_alloc (GdmXdmcpManager *manager,
- struct sockaddr_storage *mgr_sa,
- struct sockaddr_storage *dsp_sa)
+gdm_forward_query_alloc (GdmXdmcpManager *manager,
+ GdmAddress *mgr_address,
+ GdmAddress *dsp_address)
{
GdmForwardQuery *q;
int count;
@@ -1138,8 +1187,8 @@ gdm_forward_query_alloc (GdmXdmcpManager *manager,
}
q = g_new0 (GdmForwardQuery, 1);
- q->dsp_sa = g_memdup (dsp_sa, sizeof (struct sockaddr_storage));
- q->from_sa = g_memdup (mgr_sa, sizeof (struct sockaddr_storage));
+ q->dsp_address = gdm_address_copy (dsp_address);
+ q->from_address = gdm_address_copy (mgr_address);
manager->priv->forward_queries = g_slist_prepend (manager->priv->forward_queries, q);
@@ -1147,64 +1196,70 @@ gdm_forward_query_alloc (GdmXdmcpManager *manager,
}
static GdmForwardQuery *
-gdm_forward_query_lookup (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa)
+gdm_forward_query_lookup (GdmXdmcpManager *manager,
+ GdmAddress *address)
{
GSList *li;
GSList *qlist;
- GdmForwardQuery *q;
+ GdmForwardQuery *ret;
time_t curtime;
curtime = time (NULL);
+ ret = NULL;
qlist = g_slist_copy (manager->priv->forward_queries);
for (li = qlist; li != NULL; li = li->next) {
+ GdmForwardQuery *q;
+ char *host;
+ char *serv;
+
q = (GdmForwardQuery *) li->data;
- if (q == NULL)
+ if (q == NULL) {
continue;
-
- if (gdm_address_equal (q->dsp_sa, clnt_sa)) {
- g_slist_free (qlist);
- return q;
}
- if (q->acctime > 0 && curtime > q->acctime + GDM_FORWARD_QUERY_TIMEOUT) {
- char *host;
- char *serv;
+ gdm_address_get_numeric_info (q->dsp_address, &host, &serv);
- gdm_address_get_info (q->dsp_sa, &host, &serv);
+ g_debug ("gdm_forward_query_lookup: comparing %s:%s", host, serv);
+ if (gdm_address_equal (q->dsp_address, address)) {
+ ret = q;
+ g_free (host);
+ g_free (serv);
+ break;
+ }
+ if (q->acctime > 0 && curtime > q->acctime + GDM_FORWARD_QUERY_TIMEOUT) {
g_debug ("gdm_forward_query_lookup: Disposing stale forward query from %s:%s",
host, serv);
- g_free (host);
- g_free (serv);
gdm_forward_query_dispose (manager, q);
- continue;
}
+
+ g_free (host);
+ g_free (serv);
}
g_slist_free (qlist);
- {
+ if (ret == NULL) {
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("gdm_forward_query_lookup: Host %s not found",
host);
g_free (host);
}
- return NULL;
+ return ret;
}
static gboolean
-create_sa_from_request (ARRAY8 *req_addr,
- ARRAY8 *req_port,
- int family,
- struct sockaddr_storage **sap)
+create_address_from_request (ARRAY8 *req_addr,
+ ARRAY8 *req_port,
+ int family,
+ GdmAddress **address)
{
uint16_t port;
char host_buf [NI_MAXHOST];
@@ -1217,8 +1272,8 @@ create_sa_from_request (ARRAY8 *req_addr,
int gaierr;
gboolean found;
- if (sap != NULL) {
- *sap = NULL;
+ if (address != NULL) {
+ *address = NULL;
}
if (req_addr == NULL) {
@@ -1273,8 +1328,8 @@ create_sa_from_request (ARRAY8 *req_addr,
found = FALSE;
if (ai != NULL) {
found = TRUE;
- if (sap != NULL) {
- *sap = g_memdup (ai->ai_addr, ai->ai_addrlen);
+ if (address != NULL) {
+ *address = gdm_address_new_from_sockaddr_storage ((struct sockaddr_storage *)ai->ai_addr);
}
}
@@ -1284,17 +1339,17 @@ create_sa_from_request (ARRAY8 *req_addr,
}
static void
-gdm_xdmcp_whack_queued_managed_forwards (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- struct sockaddr_storage *origin)
+gdm_xdmcp_whack_queued_managed_forwards (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ GdmAddress *origin)
{
GSList *li;
for (li = manager->priv->managed_forwards; li != NULL; li = li->next) {
ManagedForward *mf = li->data;
- if (gdm_address_equal (&mf->manager, clnt_sa) &&
- gdm_address_equal (&mf->origin, origin)) {
+ if (gdm_address_equal (mf->manager, address) &&
+ gdm_address_equal (mf->origin, origin)) {
manager->priv->managed_forwards = g_slist_remove_link (manager->priv->managed_forwards, li);
g_slist_free_1 (li);
g_source_remove (mf->handler);
@@ -1305,26 +1360,26 @@ gdm_xdmcp_whack_queued_managed_forwards (GdmXdmcpManager *manager,
}
static void
-gdm_xdmcp_handle_forward_query (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_forward_query (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
ARRAY8 clnt_addr;
ARRAY8 clnt_port;
ARRAYofARRAY8 clnt_authlist;
int i;
int explen;
- struct sockaddr_storage *disp_sa;
+ GdmAddress *disp_address;
char *host;
char *serv;
- disp_sa = NULL;
+ disp_address = NULL;
/* Check with tcp_wrappers if client is allowed to access */
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_warning ("%s: Got FORWARD_QUERY from banned host %s",
"gdm_xdmcp_handle_forward query",
@@ -1377,69 +1432,71 @@ gdm_xdmcp_handle_forward_query (GdmXdmcpManager *manager,
goto out;
}
- if (! create_sa_from_request (&clnt_addr, &clnt_port, clnt_sa->ss_family, &disp_sa)) {
+ if (! create_address_from_request (&clnt_addr, &clnt_port, gdm_address_get_family_type (address), &disp_address)) {
g_warning ("Unable to parse address for request");
goto out;
}
gdm_xdmcp_whack_queued_managed_forwards (manager,
- clnt_sa,
- disp_sa);
+ address,
+ disp_address);
- gdm_address_get_info (disp_sa, &host, &serv);
+ gdm_address_get_numeric_info (disp_address, &host, &serv);
g_debug ("gdm_xdmcp_handle_forward_query: Got FORWARD_QUERY for display: %s, port %s",
host, serv);
g_free (host);
g_free (serv);
/* Check with tcp_wrappers if display is allowed to access */
- if (gdm_xdmcp_host_allow (disp_sa)) {
+ if (gdm_xdmcp_host_allow (disp_address)) {
GdmForwardQuery *q;
- q = gdm_forward_query_lookup (manager, disp_sa);
- if (q != NULL)
+ q = gdm_forward_query_lookup (manager, disp_address);
+ if (q != NULL) {
gdm_forward_query_dispose (manager, q);
+ }
- gdm_forward_query_alloc (manager, clnt_sa, disp_sa);
+ gdm_forward_query_alloc (manager, address, disp_address);
- gdm_xdmcp_send_willing (manager, disp_sa);
+ gdm_xdmcp_send_willing (manager, disp_address);
}
out:
- g_free (disp_sa);
+ gdm_address_free (disp_address);
+
XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
XdmcpDisposeARRAY8 (&clnt_port);
XdmcpDisposeARRAY8 (&clnt_addr);
}
static void
-gdm_xdmcp_really_send_managed_forward (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- struct sockaddr_storage *origin)
+gdm_xdmcp_really_send_managed_forward (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ GdmAddress *origin)
{
- ARRAY8 address;
+ ARRAY8 addr;
XdmcpHeader header;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Sending MANAGED_FORWARD to %s", host);
g_free (host);
- set_address_for_request (origin, &address);
+ set_address_for_request (origin, &addr);
header.opcode = (CARD16) GDM_XDMCP_MANAGED_FORWARD;
- header.length = 4 + address.length;
+ header.length = 4 + addr.length;
header.version = GDM_XDMCP_PROTOCOL_VERSION;
XdmcpWriteHeader (&manager->priv->buf, &header);
- XdmcpWriteARRAY8 (&manager->priv->buf, &address);
+ XdmcpWriteARRAY8 (&manager->priv->buf, &addr);
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
- g_free (address.data);
+ g_free (addr.data);
}
static gboolean
@@ -1447,8 +1504,8 @@ managed_forward_handler (ManagedForward *mf)
{
if (mf->xdmcp_manager->priv->socket_fd > 0) {
gdm_xdmcp_really_send_managed_forward (mf->xdmcp_manager,
- &(mf->manager),
- &(mf->origin));
+ mf->manager,
+ mf->origin);
}
mf->times++;
@@ -1462,161 +1519,188 @@ managed_forward_handler (ManagedForward *mf)
}
static void
-gdm_xdmcp_send_managed_forward (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- struct sockaddr_storage *origin)
+managed_forward_free (ManagedForward *mf)
+{
+ gdm_address_free (mf->origin);
+ gdm_address_free (mf->manager);
+ g_free (mf);
+}
+
+static void
+gdm_xdmcp_send_managed_forward (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ GdmAddress *origin)
{
ManagedForward *mf;
- gdm_xdmcp_really_send_managed_forward (manager, clnt_sa, origin);
+ gdm_xdmcp_really_send_managed_forward (manager, address, origin);
mf = g_new0 (ManagedForward, 1);
mf->times = 0;
mf->xdmcp_manager = manager;
- memcpy (&(mf->manager), clnt_sa, sizeof (struct sockaddr_storage));
- memcpy (&(mf->origin), origin, sizeof (struct sockaddr_storage));
+ mf->manager = gdm_address_copy (address);
+ mf->origin = gdm_address_copy (origin);
mf->handler = g_timeout_add_full (G_PRIORITY_DEFAULT,
MANAGED_FORWARD_INTERVAL,
(GSourceFunc)managed_forward_handler,
mf,
- (GDestroyNotify) g_free);
+ (GDestroyNotify)managed_forward_free);
manager->priv->managed_forwards = g_slist_prepend (manager->priv->managed_forwards, mf);
}
static void
-gdm_xdmcp_send_got_managed_forward (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- struct sockaddr_storage *origin)
+gdm_xdmcp_send_got_managed_forward (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ GdmAddress *origin)
{
- ARRAY8 address;
+ ARRAY8 addr;
XdmcpHeader header;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Sending GOT_MANAGED_FORWARD to %s", host);
g_free (host);
- set_address_for_request (origin, &address);
+ set_address_for_request (origin, &addr);
header.opcode = (CARD16) GDM_XDMCP_GOT_MANAGED_FORWARD;
- header.length = 4 + address.length;
+ header.length = 4 + addr.length;
header.version = GDM_XDMCP_PROTOCOL_VERSION;
XdmcpWriteHeader (&manager->priv->buf, &header);
- XdmcpWriteARRAY8 (&manager->priv->buf, &address);
+ XdmcpWriteARRAY8 (&manager->priv->buf, &addr);
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
}
-static void
-gdm_xdmcp_recount_sessions (GdmXdmcpManager *manager)
+static gboolean
+count_sessions (const char *id,
+ GdmDisplay *display,
+ GdmXdmcpManager *manager)
{
- GSList *li;
- GSList *displays;
+ if (GDM_IS_XDMCP_DISPLAY (display)) {
+ int status;
- displays = gdm_daemon_config_get_display_list ();
+ status = gdm_display_get_status (display);
- manager->priv->num_sessions = 0;
- manager->priv->num_pending_sessions = 0;
+ if (status == GDM_DISPLAY_MANAGED) {
+ manager->priv->num_sessions++;
+ } else if (status == GDM_DISPLAY_UNMANAGED) {
+ manager->priv->num_pending_sessions++;
+ }
+ }
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (SERVER_IS_XDMCP (d)) {
- if (d->dispstat == XDMCP_MANAGED)
- manager->priv->num_sessions++;
- else if (d->dispstat == XDMCP_PENDING)
- manager->priv->num_pending_sessions++;
- }
- }
+ return TRUE;
}
static void
-do_dispose (GdmXdmcpManager *manager,
- GdmDisplay *d)
+gdm_xdmcp_recount_sessions (GdmXdmcpManager *manager)
{
+ manager->priv->num_sessions = 0;
+ manager->priv->num_pending_sessions = 0;
- gdm_display_dispose (d);
- gdm_xdmcp_recount_sessions (manager);
+ gdm_display_store_foreach (manager->priv->display_store,
+ (GdmDisplayStoreFunc)count_sessions,
+ manager);
+}
+
+static gboolean
+purge_displays (const char *id,
+ GdmDisplay *display,
+ GdmXdmcpManager *manager)
+{
+ if (GDM_IS_XDMCP_DISPLAY (display)) {
+ int status;
+ time_t currtime;
+ time_t acctime;
+
+ currtime = time (NULL);
+ status = gdm_display_get_status (display);
+ acctime = gdm_display_get_creation_time (display);
+
+ if (status == GDM_DISPLAY_UNMANAGED &&
+ currtime > acctime + manager->priv->max_wait) {
+ /* return TRUE to remove display */
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
static void
gdm_xdmcp_displays_purge (GdmXdmcpManager *manager)
{
- GSList *dlist;
- time_t curtime = time (NULL);
- GSList *displays;
+ gdm_display_store_foreach_remove (manager->priv->display_store,
+ (GdmDisplayStoreFunc)purge_displays,
+ manager);
+
+ gdm_xdmcp_recount_sessions (manager);
+}
- displays = gdm_daemon_config_get_display_list ();
+typedef struct {
+ const char *hostname;
+ int display_num;
+} RemoveHostData;
- dlist = displays;
- while (dlist != NULL) {
- GdmDisplay *d = dlist->data;
+static gboolean
+remove_host (const char *id,
+ GdmDisplay *display,
+ RemoveHostData *data)
+{
+ char *hostname;
+ int disp_num;
- if (d != NULL &&
- SERVER_IS_XDMCP (d) &&
- d->dispstat == XDMCP_PENDING &&
- curtime > d->acctime + manager->priv->max_wait) {
- g_debug ("gdm_xdmcp_displays_purge: Disposing session id %ld",
- (long)d->sessionid);
- do_dispose (manager, d);
+ if (! GDM_IS_XDMCP_DISPLAY (display)) {
+ return FALSE;
+ }
- /* restart as the list is now broken */
- dlist = displays;
- } else {
- /* just go on */
- dlist = dlist->next;
- }
+ gdm_xdmcp_display_get_remote_hostname (GDM_XDMCP_DISPLAY (display), &hostname, NULL);
+ gdm_display_get_number (display, &disp_num, NULL);
+
+ if (disp_num == data->display_num &&
+ hostname != NULL &&
+ data->hostname != NULL &&
+ strcmp (hostname, data->hostname) == 0) {
+ /* return TRUE to remove */
+ return TRUE;
}
+
+ return FALSE;
}
static void
gdm_xdmcp_display_dispose_check (GdmXdmcpManager *manager,
const char *hostname,
- int dspnum)
+ int display_num)
{
- GSList *dlist;
- GSList *displays;
+ RemoveHostData *data;
if (hostname == NULL) {
return;
}
- g_debug ("gdm_xdmcp_display_dispose_check (%s:%d)", hostname, dspnum);
-
- displays = gdm_daemon_config_get_display_list ();
-
- dlist = displays;
- while (dlist != NULL) {
- GdmDisplay *d = dlist->data;
-
- if (d != NULL &&
- SERVER_IS_XDMCP (d) &&
- d->xdmcp_dispnum == dspnum &&
- strcmp (d->hostname, hostname) == 0) {
+ g_debug ("gdm_xdmcp_display_dispose_check (%s:%d)", hostname, display_num);
- if (d->dispstat == XDMCP_MANAGED) {
- gdm_display_unmanage (d);
- } else {
- do_dispose (manager, d);
- }
+ data = g_new0 (RemoveHostData, 1);
+ data->hostname = hostname;
+ data->display_num = display_num;
+ gdm_display_store_foreach_remove (manager->priv->display_store,
+ (GdmDisplayStoreFunc)remove_host,
+ data);
+ g_free (data);
- /* restart as the list is now broken */
- dlist = displays;
- } else {
- /* just go on */
- dlist = dlist->next;
- }
- }
+ gdm_xdmcp_recount_sessions (manager);
}
static void
-gdm_xdmcp_send_decline (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- const char *reason)
+gdm_xdmcp_send_decline (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ const char *reason)
{
XdmcpHeader header;
ARRAY8 authentype;
@@ -1625,7 +1709,7 @@ gdm_xdmcp_send_decline (GdmXdmcpManager *manager,
GdmForwardQuery *fq;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XMDCP: Sending DECLINE to %s", host);
g_free (host);
@@ -1651,133 +1735,63 @@ gdm_xdmcp_send_decline (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
/* Send MANAGED_FORWARD to indicate that the connection
* reached some sort of resolution */
- fq = gdm_forward_query_lookup (manager, clnt_sa);
+ fq = gdm_forward_query_lookup (manager, address);
if (fq != NULL) {
- gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa);
+ gdm_xdmcp_send_managed_forward (manager, fq->from_address, address);
gdm_forward_query_dispose (manager, fq);
}
}
static GdmDisplay *
gdm_xdmcp_display_alloc (GdmXdmcpManager *manager,
- struct sockaddr_storage *addr,
- GdmHostent *he /* eaten and freed */,
+ const char *hostname,
+ GdmAddress *address,
int displaynum)
{
- GdmDisplay *d = NULL;
- const char *proxycmd;
- gboolean use_proxy = FALSE;
-
- proxycmd = NULL;
- use_proxy = FALSE;
-#if 0
- proxycmd = gdm_daemon_config_get_value_string (GDM_KEY_XDMCP_PROXY_XSERVER);
- use_proxy = FALSE;
-#endif
- d = g_new0 (GdmDisplay, 1);
-
- if (use_proxy && proxycmd != NULL) {
- d->type = TYPE_XDMCP_PROXY;
- d->command = g_strdup (proxycmd);
- g_debug ("Using proxy server for XDMCP: %s\n", d->command);
- } else {
- d->type = TYPE_XDMCP;
- }
-
- d->logout_action = GDM_LOGOUT_ACTION_NONE;
- d->authfile = NULL;
- d->auths = NULL;
- d->userauth = NULL;
- d->greetpid = 0;
- d->servpid = 0;
- d->servstat = 0;
- d->sesspid = 0;
- d->slavepid = 0;
- d->attached = FALSE;
- d->dispstat = XDMCP_PENDING;
- d->sessionid = get_next_session_serial (manager);
-
- d->acctime = time (NULL);
- d->dispnum = displaynum;
- d->xdmcp_dispnum = displaynum;
-
- d->handled = TRUE;
- d->tcp_disallowed = FALSE;
- d->vt = -1;
- d->x_servers_order = -1;
- d->logged_in = FALSE;
- d->login = NULL;
- d->sleep_before_run = 0;
-
- if (gdm_daemon_config_get_value_bool (GDM_KEY_ALLOW_REMOTE_AUTOLOGIN) &&
- ! ve_string_empty (gdm_daemon_config_get_value_string (GDM_KEY_TIMED_LOGIN))) {
- d->timed_login_ok = TRUE;
- } else {
- d->timed_login_ok = FALSE;
- }
-
- d->name = g_strdup_printf ("%s:%d",
- he->hostname,
- displaynum);
-
- memcpy (&d->addr, addr, sizeof (struct sockaddr_storage));
+ GdmDisplay *display;
+ char *name;
- d->hostname = he->hostname;
- he->hostname = NULL;
- d->addrs = he->addrs;
- he->addrs = NULL;
- d->addr_count = he->addr_count;
- he->addr_count = 0;
+ name = g_strdup_printf ("%s:%d",
+ hostname,
+ displaynum);
- gdm_hostent_free (he);
-
- d->slave_notify_fd = -1;
- d->master_notify_fd = -1;
- d->xsession_errors_bytes = 0;
- d->xsession_errors_fd = -1;
- d->session_output_fd = -1;
- d->chooser_output_fd = -1;
- d->chooser_last_line = NULL;
- d->theme_name = NULL;
-
- /* Secure display with cookie */
- if G_UNLIKELY (! gdm_auth_secure_display (d)) {
- g_warning ("gdm_xdmcp_display_alloc: Error setting up cookies for %s",
- d->name);
+ display = gdm_xdmcp_display_new (displaynum,
+ name,
+ hostname,
+ address,
+ get_next_session_serial (manager));
+ if (display == NULL) {
+ goto out;
}
- if (d->type == TYPE_XDMCP_PROXY) {
- d->parent_disp = d->name;
- d->name = g_strdup (":-1");
- d->dispnum = -1;
- d->server_uid = gdm_daemon_config_get_gdmuid ();
- d->parent_auth_file = d->authfile;
- d->authfile = NULL;
+ if (! gdm_display_create_authority (display)) {
+ g_object_unref (display);
+ display = NULL;
+ goto out;
}
- gdm_daemon_config_display_list_append (d);
+ gdm_display_store_add (manager->priv->display_store, display);
manager->priv->num_pending_sessions++;
+ out:
+ g_free (name);
- g_debug ("gdm_xdmcp_display_alloc: display=%s, session id=%ld, xdmcp_pending=%d",
- d->name, (long)d->sessionid, manager->priv->num_pending_sessions);
-
- return d;
+ return display;
}
static void
-gdm_xdmcp_send_accept (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- CARD32 session_id,
- ARRAY8Ptr authentication_name,
- ARRAY8Ptr authentication_data,
- ARRAY8Ptr authorization_name,
- ARRAY8Ptr authorization_data)
+gdm_xdmcp_send_accept (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ CARD32 session_id,
+ ARRAY8Ptr authentication_name,
+ ARRAY8Ptr authentication_data,
+ ARRAY8Ptr authorization_name,
+ ARRAY8Ptr authorization_data)
{
XdmcpHeader header;
char *host;
@@ -1799,10 +1813,10 @@ gdm_xdmcp_send_accept (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Sending ACCEPT to %s with SessionID=%ld",
host,
(long)session_id);
@@ -1810,9 +1824,9 @@ gdm_xdmcp_send_accept (GdmXdmcpManager *manager,
}
static void
-gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
CARD16 clnt_dspnum;
ARRAY16 clnt_conntyp;
@@ -1825,23 +1839,22 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
int i;
gboolean mitauth;
gboolean entered;
- char *host;
+ char *hostname;
mitauth = FALSE;
entered = FALSE;
- gdm_address_get_info (clnt_sa, &host, NULL);
- g_debug ("gdm_xdmcp_handle_request: Got REQUEST from %s", host);
+ hostname = NULL;
+ gdm_address_get_numeric_info (address, &hostname, NULL);
+ g_debug ("gdm_xdmcp_handle_request: Got REQUEST from %s", hostname);
/* Check with tcp_wrappers if client is allowed to access */
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
g_warning (_("%s: Got REQUEST from banned host %s"),
"gdm_xdmcp_handle_request",
- host);
- g_free (host);
- return;
+ hostname);
+ goto out;
}
- g_free (host);
gdm_xdmcp_displays_purge (manager); /* Purge pending displays */
@@ -1849,14 +1862,14 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
if G_UNLIKELY (! XdmcpReadCARD16 (&manager->priv->buf, &clnt_dspnum)) {
g_warning (_("%s: Could not read Display Number"),
"gdm_xdmcp_handle_request");
- return;
+ goto out;
}
/* We don't care about connection type. Address says it all */
if G_UNLIKELY (! XdmcpReadARRAY16 (&manager->priv->buf, &clnt_conntyp)) {
g_warning (_("%s: Could not read Connection Type"),
"gdm_xdmcp_handle_request");
- return;
+ goto out;
}
/* This is TCP/IP - we don't care */
@@ -1864,7 +1877,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
g_warning (_("%s: Could not read Client Address"),
"gdm_xdmcp_handle_request");
XdmcpDisposeARRAY16 (&clnt_conntyp);
- return;
+ goto out;
}
/* Read authentication type */
@@ -1873,7 +1886,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
"gdm_xdmcp_handle_request");
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAY16 (&clnt_conntyp);
- return;
+ goto out;
}
/* Read authentication data */
@@ -1883,7 +1896,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAY16 (&clnt_conntyp);
XdmcpDisposeARRAY8 (&clnt_authname);
- return;
+ goto out;
}
/* Read and select from supported authorization list */
@@ -1894,7 +1907,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAY16 (&clnt_conntyp);
XdmcpDisposeARRAY8 (&clnt_authname);
- return;
+ goto out;
}
/* libXdmcp doesn't terminate strings properly so we cheat and use strncmp () */
@@ -1913,7 +1926,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAYofARRAY8 (&clnt_authorization);
XdmcpDisposeARRAY16 (&clnt_conntyp);
- return;
+ goto out;
}
/* Crude checksumming */
@@ -1930,11 +1943,9 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
explen += 2 + clnt_manufacturer.length;
if G_UNLIKELY (explen != len) {
- gdm_address_get_info (clnt_sa, &host, NULL);
g_warning (_("%s: Failed checksum from %s"),
"gdm_xdmcp_handle_request",
- host);
- g_free (host);
+ hostname);
XdmcpDisposeARRAY8 (&clnt_authname);
XdmcpDisposeARRAY8 (&clnt_authdata);
@@ -1942,7 +1953,7 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAYofARRAY8 (&clnt_authorization);
XdmcpDisposeARRAY16 (&clnt_conntyp);
- return;
+ goto out;
}
{
@@ -1959,36 +1970,42 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
/* Check if ok to manage display */
if (mitauth &&
manager->priv->num_sessions < manager->priv->max_displays &&
- (gdm_address_is_local (clnt_sa) ||
- gdm_xdmcp_num_displays_from_host (manager, clnt_sa) < manager->priv->max_displays_per_host)) {
+ (gdm_address_is_local (address) ||
+ gdm_xdmcp_num_displays_from_host (manager, address) < manager->priv->max_displays_per_host)) {
entered = TRUE;
}
if (entered) {
- GdmHostent *he;
- he = gdm_gethostbyaddr (clnt_sa);
/* Check if we are already talking to this host */
- gdm_xdmcp_display_dispose_check (manager, he->hostname, clnt_dspnum);
+ gdm_xdmcp_display_dispose_check (manager, hostname, clnt_dspnum);
if (manager->priv->num_pending_sessions >= manager->priv->max_pending_displays) {
g_debug ("gdm_xdmcp_handle_request: maximum pending");
/* Don't translate, this goes over the wire to servers where we
* don't know the charset or language, so it must be ascii */
- gdm_xdmcp_send_decline (manager, clnt_sa, "Maximum pending servers");
- gdm_hostent_free (he);
+ gdm_xdmcp_send_decline (manager, address, "Maximum pending servers");
} else {
- GdmDisplay *d;
+ GdmDisplay *display;
- d = gdm_xdmcp_display_alloc (manager,
- clnt_sa,
- he /* eaten and freed */,
- clnt_dspnum);
- if (d != NULL) {
+ display = gdm_xdmcp_display_alloc (manager,
+ hostname,
+ address,
+ clnt_dspnum);
+
+ if (display != NULL) {
ARRAY8 authentication_name;
ARRAY8 authentication_data;
ARRAY8 authorization_name;
ARRAY8 authorization_data;
+ char *binary_cookie;
+ gint32 session_number;
+
+ binary_cookie = gdm_display_get_binary_cookie (display);
+ session_number = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
+
+ /* the send accept will fail if cookie is null */
+ g_assert (binary_cookie != NULL);
authentication_name.data = NULL;
authentication_name.length = 0;
@@ -1998,13 +2015,15 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
authorization_name.data = (CARD8 *) "MIT-MAGIC-COOKIE-1";
authorization_name.length = strlen ((char *) authorization_name.data);
- authorization_data.data = (CARD8 *) d->bcookie;
+ authorization_data.data = (CARD8 *) binary_cookie;
authorization_data.length = 16;
+ g_free (binary_cookie);
+
/* the addrs are NOT copied */
gdm_xdmcp_send_accept (manager,
- clnt_sa,
- d->sessionid,
+ address,
+ session_number,
&authentication_name,
&authentication_data,
&authorization_name,
@@ -2016,18 +2035,18 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
* don't know the charset or language, so it must be ascii */
if ( ! mitauth) {
gdm_xdmcp_send_decline (manager,
- clnt_sa,
+ address,
"Only MIT-MAGIC-COOKIE-1 supported");
} else if (manager->priv->num_sessions >= manager->priv->max_displays) {
g_warning ("Maximum number of open XDMCP sessions reached");
gdm_xdmcp_send_decline (manager,
- clnt_sa,
+ address,
"Maximum number of open sessions reached");
} else {
g_debug ("Maximum number of open XDMCP sessions from host %s reached",
- host);
+ hostname);
gdm_xdmcp_send_decline (manager,
- clnt_sa,
+ address,
"Maximum number of open sessions from your host reached");
}
}
@@ -2038,40 +2057,54 @@ gdm_xdmcp_handle_request (GdmXdmcpManager *manager,
XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
XdmcpDisposeARRAYofARRAY8 (&clnt_authorization);
XdmcpDisposeARRAY16 (&clnt_conntyp);
+ out:
+ g_free (hostname);
}
-static GdmDisplay *
-gdm_xdmcp_display_lookup (GdmXdmcpManager *manager,
- CARD32 sessid)
+static gboolean
+lookup_by_session_id (const char *id,
+ GdmDisplay *display,
+ gpointer data)
{
- GSList *l;
- GdmDisplay *d;
- GSList *displays;
+ CARD32 sessid;
+ CARD32 session_id;
- if (sessid == 0) {
- return (NULL);
+ sessid = GPOINTER_TO_INT (data);
+
+ if (! GDM_IS_XDMCP_DISPLAY (display)) {
+ return FALSE;
}
- displays = gdm_daemon_config_get_display_list ();
+ session_id = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
- l = displays;
- while (l != NULL) {
- d = (GdmDisplay *) l->data;
+ if (session_id == sessid) {
+ return TRUE;
+ }
- if (d && d->sessionid == sessid) {
- return (d);
- }
+ return FALSE;
+}
+
+static GdmDisplay *
+gdm_xdmcp_display_lookup (GdmXdmcpManager *manager,
+ CARD32 sessid)
+{
+ GdmDisplay *display;
- l = l->next;
+ if (sessid == 0) {
+ return NULL;
}
- return (NULL);
+ display = gdm_display_store_find (manager->priv->display_store,
+ (GdmDisplayStoreFunc)lookup_by_session_id,
+ GINT_TO_POINTER (sessid));
+
+ return display;
}
static void
-gdm_xdmcp_send_failed (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- CARD32 sessid)
+gdm_xdmcp_send_failed (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ CARD32 sessid)
{
XdmcpHeader header;
ARRAY8 status;
@@ -2095,14 +2128,14 @@ gdm_xdmcp_send_failed (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
}
static void
-gdm_xdmcp_send_refuse (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- CARD32 sessid)
+gdm_xdmcp_send_refuse (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ CARD32 sessid)
{
XdmcpHeader header;
GdmForwardQuery *fq;
@@ -2119,38 +2152,37 @@ gdm_xdmcp_send_refuse (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
/*
* This was from a forwarded query quite apparently so
* send MANAGED_FORWARD
*/
- fq = gdm_forward_query_lookup (manager, clnt_sa);
+ fq = gdm_forward_query_lookup (manager, address);
if (fq != NULL) {
- gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa);
+ gdm_xdmcp_send_managed_forward (manager, fq->from_address, address);
gdm_forward_query_dispose (manager, fq);
}
}
static void
-gdm_xdmcp_handle_manage (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_manage (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
CARD32 clnt_sessid;
CARD16 clnt_dspnum;
ARRAY8 clnt_dspclass;
- GdmDisplay *d;
- GdmIndirectDisplay *id;
+ GdmDisplay *display;
GdmForwardQuery *fq;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("gdm_xdmcp_handle_manage: Got MANAGE from %s", host);
/* Check with tcp_wrappers if client is allowed to access */
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
g_warning (_("%s: Got Manage from banned host %s"),
"gdm_xdmcp_handle_manage",
host);
@@ -2180,7 +2212,7 @@ gdm_xdmcp_handle_manage (GdmXdmcpManager *manager,
return;
}
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG)) {
+ {
char *s = g_strndup ((char *) clnt_dspclass.data, clnt_dspclass.length);
g_debug ("gdm_xdmcp-handle_manage: Got display=%d, SessionID=%ld Class=%s from %s",
(int)clnt_dspnum, (long)clnt_sessid, ve_sure_string (s), host);
@@ -2188,79 +2220,84 @@ gdm_xdmcp_handle_manage (GdmXdmcpManager *manager,
g_free (s);
}
- d = gdm_xdmcp_display_lookup (manager, clnt_sessid);
- if (d != NULL &&
- d->dispstat == XDMCP_PENDING) {
+ display = gdm_xdmcp_display_lookup (manager, clnt_sessid);
+ if (display != NULL &&
+ gdm_display_get_status (display) == GDM_DISPLAY_UNMANAGED) {
+ char *name;
+
+ name = NULL;
+ gdm_display_get_name (display, &name, NULL);
+ g_debug ("gdm_xdmcp_handle_manage: Looked up %s", name);
+ g_free (name);
- g_debug ("gdm_xdmcp_handle_manage: Looked up %s", d->name);
+#if 0 /* FIXME: */
+ if (manager->priv->honor_indirect) {
+ GdmIndirectDisplay *id;
- if (gdm_daemon_config_get_value_bool (GDM_KEY_INDIRECT)) {
- id = gdm_choose_indirect_lookup (clnt_sa);
+ id = gdm_choose_indirect_lookup (address);
/* This was an indirect thingie and nothing was yet chosen,
* use a chooser */
- if (d->dispstat == XDMCP_PENDING &&
- id != NULL &&
+ if (id != NULL &&
id->chosen_host == NULL) {
d->use_chooser = TRUE;
d->indirect_id = id->id;
} else {
d->indirect_id = 0;
d->use_chooser = FALSE;
- if (id != NULL)
+ if (id != NULL) {
gdm_choose_indirect_dispose (id);
+ }
}
} else {
- d->indirect_id = 0;
- d->use_chooser = FALSE;
- }
+ }
+#endif
/* this was from a forwarded query quite apparently so
* send MANAGED_FORWARD */
- fq = gdm_forward_query_lookup (manager, clnt_sa);
+ fq = gdm_forward_query_lookup (manager, address);
if (fq != NULL) {
- gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa);
+ gdm_xdmcp_send_managed_forward (manager, fq->from_address, address);
gdm_forward_query_dispose (manager, fq);
}
- d->dispstat = XDMCP_MANAGED;
manager->priv->num_sessions++;
manager->priv->num_pending_sessions--;
/* Start greeter/session */
- if G_UNLIKELY (!gdm_display_manage (d)) {
- gdm_xdmcp_send_failed (manager, clnt_sa, clnt_sessid);
- XdmcpDisposeARRAY8 (&clnt_dspclass);
- return;
+ if (! gdm_display_manage (display)) {
+ gdm_xdmcp_send_failed (manager, address, clnt_sessid);
+ g_debug ("Failed to manage display");
}
- } else if G_UNLIKELY (d != NULL && d->dispstat == XDMCP_MANAGED) {
+ } else if (display != NULL &&
+ gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
g_debug ("gdm_xdmcp_handle_manage: Session id %ld already managed",
- (long)clnt_sessid);
+ (long)clnt_sessid);
} else {
g_warning ("gdm_xdmcp_handle_manage: Failed to look up session id %ld",
(long)clnt_sessid);
- gdm_xdmcp_send_refuse (manager, clnt_sa, clnt_sessid);
+ gdm_xdmcp_send_refuse (manager, address, clnt_sessid);
}
XdmcpDisposeARRAY8 (&clnt_dspclass);
}
static void
-gdm_xdmcp_handle_managed_forward (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_managed_forward (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
ARRAY8 clnt_address;
GdmIndirectDisplay *id;
char *host;
- struct sockaddr_storage *disp_sa;
+ GdmAddress *disp_address;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("gdm_xdmcp_handle_managed_forward: Got MANAGED_FORWARD from %s",
host);
/* Check with tcp_wrappers if client is allowed to access */
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
g_warning ("%s: Got MANAGED_FORWARD from banned host %s",
"gdm_xdmcp_handle_request", host);
g_free (host);
@@ -2275,39 +2312,41 @@ gdm_xdmcp_handle_managed_forward (GdmXdmcpManager *manager,
return;
}
- disp_sa = NULL;
- if (! create_sa_from_request (&clnt_address, NULL, clnt_sa->ss_family, &disp_sa)) {
+ disp_address = NULL;
+ if (! create_address_from_request (&clnt_address, NULL, gdm_address_get_family_type (address), &disp_address)) {
g_warning ("Unable to parse address for request");
XdmcpDisposeARRAY8 (&clnt_address);
return;
}
- id = gdm_choose_indirect_lookup_by_chosen (clnt_sa, disp_sa);
+ id = gdm_choose_indirect_lookup_by_chosen (address, disp_address);
if (id != NULL) {
gdm_choose_indirect_dispose (id);
}
/* Note: we send GOT even on not found, just in case our previous
* didn't get through and this was a second managed forward */
- gdm_xdmcp_send_got_managed_forward (manager, clnt_sa, disp_sa);
+ gdm_xdmcp_send_got_managed_forward (manager, address, disp_address);
+
+ gdm_address_free (disp_address);
XdmcpDisposeARRAY8 (&clnt_address);
}
static void
-gdm_xdmcp_handle_got_managed_forward (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_got_managed_forward (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
- struct sockaddr_storage *disp_sa;
- ARRAY8 clnt_address;
- char *host;
+ GdmAddress *disp_address;
+ ARRAY8 clnt_address;
+ char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("gdm_xdmcp_handle_got_managed_forward: Got MANAGED_FORWARD from %s",
host);
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
g_warning ("%s: Got GOT_MANAGED_FORWARD from banned host %s",
"gdm_xdmcp_handle_request", host);
g_free (host);
@@ -2322,37 +2361,43 @@ gdm_xdmcp_handle_got_managed_forward (GdmXdmcpManager *manager,
return;
}
- if (! create_sa_from_request (&clnt_address, NULL, clnt_sa->ss_family, &disp_sa)) {
+ if (! create_address_from_request (&clnt_address, NULL, gdm_address_get_family_type (address), &disp_address)) {
g_warning (_("%s: Could not read address"),
"gdm_xdmcp_handle_got_managed_forward");
XdmcpDisposeARRAY8 (&clnt_address);
return;
}
- gdm_xdmcp_whack_queued_managed_forwards (manager, clnt_sa, disp_sa);
+ gdm_xdmcp_whack_queued_managed_forwards (manager, address, disp_address);
+
+ gdm_address_free (disp_address);
XdmcpDisposeARRAY8 (&clnt_address);
}
static void
-gdm_xdmcp_send_alive (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- CARD16 dspnum,
- CARD32 sessid)
+gdm_xdmcp_send_alive (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ CARD16 dspnum,
+ CARD32 sessid)
{
XdmcpHeader header;
- GdmDisplay *d;
- int send_running = 0;
- CARD32 send_sessid = 0;
+ GdmDisplay *display;
+ int send_running = 0;
+ CARD32 send_sessid = 0;
- d = gdm_xdmcp_display_lookup (manager, sessid);
- if (d == NULL) {
- d = gdm_xdmcp_display_lookup_by_host (manager, clnt_sa, dspnum);
+ display = gdm_xdmcp_display_lookup (manager, sessid);
+ if (display == NULL) {
+ display = gdm_xdmcp_display_lookup_by_host (manager, address, dspnum);
}
- if (d != NULL) {
- send_sessid = d->sessionid;
- if (d->dispstat == XDMCP_MANAGED) {
+ if (display != NULL) {
+ int status;
+
+ send_sessid = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
+ status = gdm_display_get_status (display);
+
+ if (status == GDM_DISPLAY_MANAGED) {
send_running = 1;
}
}
@@ -2372,24 +2417,24 @@ gdm_xdmcp_send_alive (GdmXdmcpManager *manager,
XdmcpFlush (manager->priv->socket_fd,
&manager->priv->buf,
- (XdmcpNetaddr)clnt_sa,
+ (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)sizeof (struct sockaddr_storage));
}
static void
-gdm_xdmcp_handle_keepalive (GdmXdmcpManager *manager,
- struct sockaddr_storage *clnt_sa,
- int len)
+gdm_xdmcp_handle_keepalive (GdmXdmcpManager *manager,
+ GdmAddress *address,
+ int len)
{
CARD16 clnt_dspnum;
CARD32 clnt_sessid;
char *host;
- gdm_address_get_info (clnt_sa, &host, NULL);
+ gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("XDMCP: Got KEEPALIVE from %s", host);
/* Check with tcp_wrappers if client is allowed to access */
- if (! gdm_xdmcp_host_allow (clnt_sa)) {
+ if (! gdm_xdmcp_host_allow (address)) {
g_warning (_("%s: Got KEEPALIVE from banned host %s"),
"gdm_xdmcp_handle_keepalive",
host);
@@ -2412,7 +2457,7 @@ gdm_xdmcp_handle_keepalive (GdmXdmcpManager *manager,
return;
}
- gdm_xdmcp_send_alive (manager, clnt_sa, clnt_dspnum, clnt_sessid);
+ gdm_xdmcp_send_alive (manager, address, clnt_dspnum, clnt_sessid);
}
static const char *
@@ -2456,22 +2501,22 @@ decode_packet (GIOChannel *source,
GIOCondition cond,
GdmXdmcpManager *manager)
{
- struct sockaddr_storage clnt_sa;
- gint sa_len;
+ struct sockaddr_storage clnt_ss;
+ GdmAddress *address;
+ gint ss_len;
XdmcpHeader header;
char *host;
char *port;
int res;
- sa_len = sizeof (clnt_sa);
-
g_debug ("decode_packet: GIOCondition %d", (int)cond);
if ( ! (cond & G_IO_IN)) {
return TRUE;
}
- res = XdmcpFill (manager->priv->socket_fd, &manager->priv->buf, (XdmcpNetaddr)&clnt_sa, &sa_len);
+ ss_len = sizeof (clnt_ss);
+ res = XdmcpFill (manager->priv->socket_fd, &manager->priv->buf, (XdmcpNetaddr)&clnt_ss, &ss_len);
if G_UNLIKELY (! res) {
g_debug (_("XMCP: Could not create XDMCP buffer!"));
return TRUE;
@@ -2489,7 +2534,13 @@ decode_packet (GIOChannel *source,
return TRUE;
}
- gdm_address_get_info (&clnt_sa, &host, &port);
+ address = gdm_address_new_from_sockaddr_storage (&clnt_ss);
+ if (address == NULL) {
+ g_warning (_("XMDCP: Unable to parse address"));
+ return TRUE;
+ }
+
+ gdm_address_get_numeric_info (address, &host, &port);
g_debug ("XDMCP: Received opcode %s from client %s : %s",
opcode_string (header.opcode),
@@ -2498,39 +2549,39 @@ decode_packet (GIOChannel *source,
switch (header.opcode) {
case BROADCAST_QUERY:
- gdm_xdmcp_handle_broadcast_query (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_broadcast_query (manager, address, header.length);
break;
case QUERY:
- gdm_xdmcp_handle_query (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_query (manager, address, header.length);
break;
case INDIRECT_QUERY:
- gdm_xdmcp_handle_indirect_query (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_indirect_query (manager, address, header.length);
break;
case FORWARD_QUERY:
- gdm_xdmcp_handle_forward_query (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_forward_query (manager, address, header.length);
break;
case REQUEST:
- gdm_xdmcp_handle_request (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_request (manager, address, header.length);
break;
case MANAGE:
- gdm_xdmcp_handle_manage (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_manage (manager, address, header.length);
break;
case KEEPALIVE:
- gdm_xdmcp_handle_keepalive (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_keepalive (manager, address, header.length);
break;
case GDM_XDMCP_MANAGED_FORWARD:
- gdm_xdmcp_handle_managed_forward (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_managed_forward (manager, address, header.length);
break;
case GDM_XDMCP_GOT_MANAGED_FORWARD:
- gdm_xdmcp_handle_got_managed_forward (manager, &clnt_sa, header.length);
+ gdm_xdmcp_handle_got_managed_forward (manager, address, header.length);
break;
default:
@@ -2544,6 +2595,8 @@ decode_packet (GIOChannel *source,
g_free (host);
g_free (port);
+ gdm_address_free (address);
+
return TRUE;
}
@@ -2684,6 +2737,20 @@ gdm_xdmcp_manager_set_willing_script (GdmXdmcpManager *manager,
}
static void
+gdm_xdmcp_manager_set_display_store (GdmXdmcpManager *manager,
+ GdmDisplayStore *display_store)
+{
+ if (manager->priv->display_store != NULL) {
+ g_object_unref (manager->priv->display_store);
+ manager->priv->display_store = NULL;
+ }
+
+ if (display_store != NULL) {
+ manager->priv->display_store = g_object_ref (display_store);
+ }
+}
+
+static void
gdm_xdmcp_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -2694,6 +2761,9 @@ gdm_xdmcp_manager_set_property (GObject *object,
self = GDM_XDMCP_MANAGER (object);
switch (prop_id) {
+ case PROP_DISPLAY_STORE:
+ gdm_xdmcp_manager_set_display_store (self, g_value_get_object (value));
+ break;
case PROP_PORT:
gdm_xdmcp_manager_set_port (self, g_value_get_uint (value));
break;
@@ -2738,6 +2808,9 @@ gdm_xdmcp_manager_get_property (GObject *object,
self = GDM_XDMCP_MANAGER (object);
switch (prop_id) {
+ case PROP_DISPLAY_STORE:
+ g_value_set_object (value, self->priv->display_store);
+ break;
case PROP_PORT:
g_value_set_uint (value, self->priv->port);
break;
@@ -2781,6 +2854,13 @@ gdm_xdmcp_manager_class_init (GdmXdmcpManagerClass *klass)
object_class->finalize = gdm_xdmcp_manager_finalize;
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_object_class_install_property (object_class,
PROP_PORT,
g_param_spec_uint ("port",
"UDP port",
@@ -2918,12 +2998,14 @@ gdm_xdmcp_manager_finalize (GObject *object)
}
GdmXdmcpManager *
-gdm_xdmcp_manager_new (void)
+gdm_xdmcp_manager_new (GdmDisplayStore *store)
{
if (xdmcp_manager_object != NULL) {
g_object_ref (xdmcp_manager_object);
} else {
- xdmcp_manager_object = g_object_new (GDM_TYPE_XDMCP_MANAGER, NULL);
+ xdmcp_manager_object = g_object_new (GDM_TYPE_XDMCP_MANAGER,
+ "display-store", store,
+ NULL);
g_object_add_weak_pointer (xdmcp_manager_object,
(gpointer *) &xdmcp_manager_object);
}
diff --git a/daemon/gdm-xdmcp-manager.h b/daemon/gdm-xdmcp-manager.h
index fe12ddc5..ffa1c57a 100644
--- a/daemon/gdm-xdmcp-manager.h
+++ b/daemon/gdm-xdmcp-manager.h
@@ -24,6 +24,8 @@
#include <glib-object.h>
+#include "gdm-display-store.h"
+
G_BEGIN_DECLS
#define GDM_TYPE_XDMCP_MANAGER (gdm_xdmcp_manager_get_type ())
@@ -56,7 +58,7 @@ typedef enum
GQuark gdm_xdmcp_manager_error_quark (void);
GType gdm_xdmcp_manager_get_type (void);
-GdmXdmcpManager * gdm_xdmcp_manager_new (void);
+GdmXdmcpManager * gdm_xdmcp_manager_new (GdmDisplayStore *display_store);
void gdm_xdmcp_manager_set_port (GdmXdmcpManager *manager,
guint port);
diff --git a/daemon/gdm.c b/daemon/gdm.c
deleted file mode 100644
index 19e382b4..00000000
--- a/daemon/gdm.c
+++ /dev/null
@@ -1,4334 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * GDM - The GNOME Display Manager
- * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
- *
- * 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 <signal.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
-#include <sched.h>
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/resource.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <locale.h>
-#include <dirent.h>
-
-#ifdef HAVE_CHKAUTHATTR
-#include <auth_attr.h>
-#include <secdb.h>
-#endif
-
-/* This should be moved to auth.c I suppose */
-
-#include <X11/Xauth.h>
-#include <glib/gi18n.h>
-#include <glib-object.h>
-
-#include <gtk/gtk.h>
-
-/* Needed for signal handling */
-#include "gdm-common.h"
-
-#include "gdm.h"
-#include "misc.h"
-#include "slave.h"
-#include "server.h"
-#include "verify.h"
-#include "display.h"
-#include "choose.h"
-#include "getvt.h"
-#include "gdm-net.h"
-#include "cookie.h"
-#include "filecheck.h"
-#include "errorgui.h"
-
-#include "gdm-socket-protocol.h"
-#include "gdm-daemon-config.h"
-#include "gdm-log.h"
-
-#include "xdmcp.h"
-
-#define DYNAMIC_ADD 0
-#define DYNAMIC_RELEASE 1
-#define DYNAMIC_REMOVE 2
-
-#ifdef HAVE_LOGINDEVPERM
-#include <libdevinfo.h>
-#endif /* HAVE_LOGINDEVPERM */
-
-/* Local functions */
-static void gdm_handle_message (GdmConnection *conn,
- const gchar *msg,
- gpointer data);
-static void gdm_handle_user_message (GdmConnection *conn,
- const gchar *msg,
- gpointer data);
-static void gdm_daemonify (void);
-static void gdm_safe_restart (void);
-static void gdm_try_logout_action (GdmDisplay *disp);
-static void gdm_restart_now (void);
-static void handle_flexi_server (GdmConnection *conn,
- int type,
- const gchar *server,
- gboolean handled,
- gboolean chooser,
- const gchar *xnest_disp,
- uid_t xnest_uid,
- const gchar *xnest_auth_file,
- const gchar *xnest_cookie,
- const gchar *username);
-static void custom_cmd_restart (long cmd_id);
-static void custom_cmd_no_restart (long cmd_id);
-
-/* Global vars */
-
-gint flexi_servers = 0; /* Number of flexi servers */
-static pid_t extra_process = 0; /* An extra process. Used for quickie
- processes, so that they also get whacked */
-static int extra_status = 0; /* Last status from the last extra process */
-
-gboolean gdm_wait_for_go = FALSE; /* wait for a GO in the fifo */
-static gboolean print_version = FALSE; /* print version number and quit */
-static gboolean preserve_ld_vars = FALSE; /* Preserve the ld environment
- variables */
-static gboolean no_daemon = FALSE; /* Do not daemonize */
-static gboolean no_console = FALSE; /* There are no static servers, this
- means, don't run static servers
- and second, don't display info on
- the console */
-
-GdmConnection *fifoconn = NULL; /* Fifo connection */
-GdmConnection *pipeconn = NULL; /* slavepipe (handled just like Fifo for
- compatibility) connection */
-GdmConnection *unixconn = NULL; /* UNIX Socket connection */
-int slave_fifo_pipe_fd = -1; /* The slavepipe connection */
-
-unsigned char *gdm_global_cookie = NULL;
-unsigned char *gdm_global_bcookie = NULL;
-
-gboolean gdm_first_login = TRUE;
-
-static GdmLogoutAction safe_logout_action = GDM_LOGOUT_ACTION_NONE;
-
-/* set in the main function */
-gchar **stored_argv = NULL;
-int stored_argc = 0;
-
-static GMainLoop *main_loop = NULL;
-static gchar *config_file = NULL;
-static gboolean gdm_restart_mode = FALSE;
-static gboolean monte_carlo_sqrt2 = FALSE;
-
-/*
- * Lookup display number if the display number is
- * exists then clear the remove flag and return TRUE
- * otherwise return FALSE.
- */
-static gboolean
-mark_display_exists (int num)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (disp->dispnum == num) {
- disp->removeconf = FALSE;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * gdm_daemonify:
- *
- * Detach gdm daemon from the controlling terminal
- */
-static void
-gdm_daemonify (void)
-{
- FILE *pf;
- pid_t pid;
-
- pid = fork ();
- if (pid > 0) {
- const char *pidfile = GDM_PID_FILE;
-
- errno = 0;
- if ((pf = gdm_safe_fopen_w (pidfile, 0644)) != NULL) {
- errno = 0;
- VE_IGNORE_EINTR (fprintf (pf, "%d\n", (int)pid));
- VE_IGNORE_EINTR (fclose (pf));
- if G_UNLIKELY (errno != 0) {
- /* FIXME: how to handle this? */
- gdm_fdprintf (2, _("Cannot write PID file %s: possibly out of diskspace. Error: %s\n"),
- pidfile, strerror (errno));
- gdm_error (_("Cannot write PID file %s: possibly out of diskspace. Error: %s"),
- pidfile, strerror (errno));
-
- }
- } else if G_UNLIKELY (errno != 0) {
- /* FIXME: how to handle this? */
- gdm_fdprintf (2, _("Cannot write PID file %s: possibly out of diskspace. Error: %s\n"),
- pidfile, strerror (errno));
- gdm_error (_("Cannot write PID file %s: possibly out of diskspace. Error: %s"),
- pidfile, strerror (errno));
-
- }
-
- exit (EXIT_SUCCESS);
- }
-
- if G_UNLIKELY (pid < 0)
- gdm_fail (_("%s: fork () failed!"), "gdm_daemonify");
-
- if G_UNLIKELY (setsid () < 0)
- gdm_fail (_("%s: setsid () failed: %s!"), "gdm_daemonify",
- strerror (errno));
-
- VE_IGNORE_EINTR (g_chdir (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR)));
- umask (022);
-
- VE_IGNORE_EINTR (close (0));
- VE_IGNORE_EINTR (close (1));
- VE_IGNORE_EINTR (close (2));
-
- gdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
- gdm_open_dev_null (O_RDWR); /* open stdout - fd 1 */
- gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
-}
-
-static void
-gdm_start_first_unborn_local (int delay)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- /* tickle the random stuff */
- gdm_random_tick ();
-
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
-
- if (d != NULL &&
- d->type == TYPE_STATIC &&
- d->dispstat == DISPLAY_UNBORN) {
- GdmXserver *svr;
- g_debug ("gdm_start_first_unborn_local: "
- "Starting %s", d->name);
-
- /* well sleep at least 'delay' seconds
- * before starting */
- d->sleep_before_run = delay;
-
- /* only the first static display has
- * timed login going on */
- if (gdm_first_login)
- d->timed_login_ok = TRUE;
-
- svr = gdm_server_resolve (d);
-
- if ( ! gdm_display_manage (d)) {
- gdm_display_unmanage (d);
- /* only the first static display where
- we actually log in gets
- autologged in */
- if (svr != NULL &&
- svr->handled &&
- ! svr->chooser)
- gdm_first_login = FALSE;
- } else {
- /* only the first static display where
- we actually log in gets
- autologged in */
- if (svr != NULL &&
- svr->handled &&
- ! svr->chooser)
- gdm_first_login = FALSE;
- break;
- }
- }
- }
-}
-
-void
-gdm_final_cleanup (void)
-{
- GSList *list, *li;
- const char *pidfile;
- gboolean first;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- g_debug ("gdm_final_cleanup");
-
- if (extra_process > 1) {
- /* we sigterm extra processes, and we
- * don't wait */
- kill (-(extra_process), SIGTERM);
- extra_process = 0;
- }
-
- /* First off whack all XDMCP and FLEXI_XNEST
- slaves, we'll wait for them later */
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (SERVER_IS_XDMCP (d) ||
- SERVER_IS_PROXY (d)) {
- /* set to DEAD so that we won't kill it again */
- d->dispstat = DISPLAY_DEAD;
- if (d->slavepid > 1)
- kill (d->slavepid, SIGTERM);
- }
- }
-
- /* Now completely unmanage the static servers */
- first = TRUE;
- list = g_slist_copy (displays);
- /* somewhat of a hack to kill last server
- * started first. This mostly makes things end up on
- * the right vt */
- list = g_slist_reverse (list);
- for (li = list; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (SERVER_IS_XDMCP (d) ||
- SERVER_IS_PROXY (d))
- continue;
- /* HACK! Wait 2 seconds between killing of static servers
- * because X is stupid and full of races and will otherwise
- * hang my keyboard */
- if ( ! first) {
- /* there could be signals happening
- here */
- gdm_sleep_no_signal (2);
- }
- first = FALSE;
- gdm_display_unmanage (d);
- }
- g_slist_free (list);
-
- /* and now kill and wait for the XDMCP and FLEXI_XNEST
- slaves. unmanage will not kill slaves we have already
- killed unless a SIGTERM was sent in the meantime */
-
- list = g_slist_copy (displays);
- for (li = list; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (SERVER_IS_XDMCP (d) ||
- SERVER_IS_PROXY (d))
- gdm_display_unmanage (d);
- }
- g_slist_free (list);
-
- /* Close stuff */
-
- if (gdm_daemon_config_get_value_bool (GDM_KEY_XDMCP))
- gdm_xdmcp_close ();
-
- if (fifoconn != NULL) {
- char *path;
- gdm_connection_close (fifoconn);
- path = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), ".gdmfifo", NULL);
- VE_IGNORE_EINTR (g_unlink (path));
- g_free (path);
- fifoconn = NULL;
- }
-
- if (pipeconn != NULL) {
- gdm_connection_close (pipeconn);
- pipeconn = NULL;
- }
-
- if (slave_fifo_pipe_fd >= 0) {
- VE_IGNORE_EINTR (close (slave_fifo_pipe_fd));
- slave_fifo_pipe_fd = -1;
- }
-
- if (unixconn != NULL) {
- gdm_connection_close (unixconn);
- VE_IGNORE_EINTR (g_unlink (GDM_SUP_SOCKET));
- unixconn = NULL;
- }
-
- pidfile = GDM_PID_FILE;
- if (pidfile != NULL) {
- VE_IGNORE_EINTR (g_unlink (pidfile));
- }
-
-#ifdef HAVE_LOGINDEVPERM
- (void) di_devperm_logout ("/dev/console");
-#endif /* HAVE_LOGINDEVPERM */
-}
-
-#ifdef __sun
-void
-gdm_rmdir (char *thedir)
-{
- DIR *odir;
- struct stat buf;
- struct dirent *dp;
- char thefile[FILENAME_MAX];
-
- if ((stat(thedir, &buf) == -1) || ! S_ISDIR(buf.st_mode))
- return ;
-
- if ((rmdir (thedir) == -1) && (errno == EEXIST))
- {
- odir = opendir (thedir);
- do {
- errno = 0;
- if ((dp = readdir (odir)) != NULL)
- {
- if (strcmp (dp->d_name, ".") == 0 ||
- strcmp (dp->d_name, "..") == 0)
- continue ;
- snprintf (thefile, FILENAME_MAX, "%s/%s", thedir, dp->d_name);
- if (stat (thefile, &buf) == -1)
- continue ;
- if (S_ISDIR(buf.st_mode))
- gdm_rmdir (thefile);
- else
- g_unlink (thefile);
- }
- } while (dp != NULL);
- closedir (odir);
- rmdir (thedir);
- }
-}
-#endif
-
-static gboolean
-deal_with_x_crashes (GdmDisplay *d)
-{
- gboolean just_abort = FALSE;
- const char *failsafe = gdm_daemon_config_get_value_string (GDM_KEY_FAILSAFE_XSERVER);
- const char *keepscrashing = gdm_daemon_config_get_value_string (GDM_KEY_X_KEEPS_CRASHING);
-
- if ( ! d->failsafe_xserver &&
- ! ve_string_empty (failsafe)) {
- char *bin = ve_first_word (failsafe);
- /* Yay we have a failsafe */
- if ( ! ve_string_empty (bin) &&
- g_access (bin, X_OK) == 0) {
- gdm_info (_("%s: Trying failsafe X "
- "server %s"),
- "deal_with_x_crashes",
- failsafe);
- g_free (bin);
- g_free (d->command);
- d->command = g_strdup (failsafe);
- d->failsafe_xserver = TRUE;
- return TRUE;
- }
- g_free (bin);
- }
-
- /* Eeek X keeps crashing, let's try the XKeepsCrashing script */
- if ( ! ve_string_empty (keepscrashing) &&
- g_access (keepscrashing, X_OK|R_OK) == 0) {
- pid_t pid;
-
- gdm_info (_("%s: Running the "
- "XKeepsCrashing script"),
- "deal_with_x_crashes");
-
- extra_process = pid = fork ();
- if (pid < 0)
- extra_process = 0;
-
- if (pid == 0) {
- char *argv[2];
- char *xlog = gdm_make_filename (gdm_daemon_config_get_value_string (GDM_KEY_LOG_DIR), d->name, ".log");
-
- gdm_unset_signals ();
-
- /* Also make a new process group so that we may use
- * kill -(extra_process) to kill extra process and all its
- * possible children */
- setsid ();
-
- if (gdm_daemon_config_get_value_bool (GDM_KEY_XDMCP))
- gdm_xdmcp_close ();
-
- gdm_close_all_descriptors (0 /* from */, -1 /* except */, -1 /* except2 */);
-
- /* No error checking here - if it's messed the best response
- * is to ignore & try to continue */
- gdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
- gdm_open_dev_null (O_RDWR); /* open stdout - fd 1 */
- gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
-
- argv[0] = (char *)gdm_daemon_config_get_value_string (GDM_KEY_X_KEEPS_CRASHING);
- argv[1] = NULL;
-
- gdm_restoreenv ();
-
- /* unset DISPLAY and XAUTHORITY if they exist
- * so that gdialog (if used) doesn't get confused */
- g_unsetenv ("DISPLAY");
- g_unsetenv ("XAUTHORITY");
-
- /* some promised variables */
- g_setenv ("XLOG", xlog, TRUE);
- g_setenv ("BINDIR", BINDIR, TRUE);
- g_setenv ("SBINDIR", SBINDIR, TRUE);
- g_setenv ("LIBEXECDIR", LIBEXECDIR, TRUE);
- g_setenv ("SYSCONFDIR", GDMCONFDIR, TRUE);
-
- /* To enable gettext stuff in the script */
- g_setenv ("TEXTDOMAIN", GETTEXT_PACKAGE, TRUE);
- g_setenv ("TEXTDOMAINDIR", GNOMELOCALEDIR, TRUE);
-
- if ( ! gdm_ok_console_language ()) {
- g_unsetenv ("LANG");
- g_unsetenv ("LC_ALL");
- g_unsetenv ("LC_MESSAGES");
- g_setenv ("LANG", "C", TRUE);
- g_setenv ("UNSAFE_TO_TRANSLATE", "yes", TRUE);
- }
-
- VE_IGNORE_EINTR (execv (argv[0], argv));
-
- /* yaikes! */
- _exit (32);
- } else if (pid > 0) {
- int status;
-
- if (extra_process > 1) {
- int ret;
- int killsignal = SIGTERM;
- int storeerrno;
- errno = 0;
- ret = waitpid (extra_process, &status, WNOHANG);
- do {
- /* wait for some signal, yes this is a race */
- if (ret <= 0)
- sleep (10);
- errno = 0;
- ret = waitpid (extra_process, &status, WNOHANG);
- storeerrno = errno;
- if ((ret <= 0) && gdm_daemon_config_signal_terminthup_was_notified ()) {
- kill (-(extra_process), killsignal);
- killsignal = SIGKILL;
- }
- } while (ret == 0 || (ret < 0 && storeerrno == EINTR));
- }
- extra_process = 0;
-
- if (WIFEXITED (status) &&
- WEXITSTATUS (status) == 0) {
- /* Yay, the user wants to try again, so
- * here we go */
- return TRUE;
- } else if (WIFEXITED (status) &&
- WEXITSTATUS (status) == 32) {
- /* We couldn't run the script, just drop through */
- ;
- } else {
- /* Things went wrong. */
- just_abort = TRUE;
- }
- }
-
- /* if we failed to fork, or something else has happened,
- * we fall through to the other options below */
- }
-
- /* if we have "open" we can talk to the user, not as user
- * friendly as the above script, but getting there */
- if ( ! just_abort &&
- g_access (LIBEXECDIR "/gdmopen", X_OK) == 0) {
- /* Shit if we knew what the program was to tell the user,
- * the above script would have been defined and we'd run
- * it for them */
- const char *error =
- C_(N_("The X server (your graphical interface) "
- "cannot be started. It is likely that it is not "
- "set up correctly. You will need to log in on a "
- "console and rerun the X configuration "
- "application, then restart GDM."));
- gdm_text_message_dialog (error);
- } /* else {
- * At this point .... screw the user, we don't know how to
- * talk to him. He's on some 'l33t system anyway, so syslog
- * reading will do him good
- * } */
-
- gdm_error (_("Failed to start X server several times in a short time period; disabling display %s"), d->name);
-
- return FALSE;
-}
-
-static gboolean
-try_command (const char *command,
- int *statusp)
-{
- GError *error;
- gboolean res;
- int status;
-
- g_debug ("Running %s", command);
-
- error = NULL;
- res = g_spawn_command_line_sync (command, NULL, NULL, &status, &error);
- if (error != NULL) {
- g_warning ("Command failed %s: %s", command, error->message);
- g_error_free (error);
- }
-
- *statusp = 0;
-
- if (WIFEXITED (status)) {
- *statusp = WEXITSTATUS (status);
- }
-
- return res;
-}
-
-static gboolean
-try_commands (const char **array)
-{
- int i;
- int status;
- gboolean ret;
-
- ret = FALSE;
-
- /* the idea here is to try the first available command and return if it succeeded */
-
- for (i = 0; array[i] != NULL; i++) {
- if (try_command (array[i], &status)) {
- ret = (status == 0);
-
- if (! ret) {
- gdm_error (_("command failed %s: %d"), array[i], status);
- }
-
- break;
- }
- }
-
- return ret;
-}
-
-static void
-suspend_machine (void)
-{
- const gchar **suspend;
-
- suspend = gdm_daemon_config_get_value_string_array (GDM_KEY_SUSPEND);
-
- gdm_info (_("Master suspending..."));
-
- if (suspend == NULL) {
- return;
- }
-
- try_commands (suspend);
-}
-
-#ifdef __linux__
-static void
-change_to_first_and_clear (gboolean restart)
-{
- gdm_change_vt (1);
- VE_IGNORE_EINTR (close (0));
- VE_IGNORE_EINTR (close (1));
- VE_IGNORE_EINTR (close (2));
- VE_IGNORE_EINTR (open ("/dev/tty1", O_WRONLY));
- VE_IGNORE_EINTR (open ("/dev/tty1", O_WRONLY));
- VE_IGNORE_EINTR (open ("/dev/tty1", O_WRONLY));
-
- g_setenv ("TERM", "linux", TRUE);
-
- /* evil hack that will get the fonts right */
- if (g_access ("/bin/bash", X_OK) == 0)
- system ("/bin/bash -l -c /bin/true");
-
- /* clear screen and set to red */
- printf ("\033[H\033[J\n\n\033[1m---\n\033[1;31m ");
-
- if (restart)
- printf (_("System is restarting, please wait ..."));
- else
- printf (_("System is shutting down, please wait ..."));
- /* set to black */
- printf ("\033[0m\n\033[1m---\033[0m\n\n");
-}
-#endif /* __linux__ */
-
-static void
-halt_machine (void)
-{
- const char **s;
-
- g_debug (_("Master halting..."));
-
- s = gdm_daemon_config_get_value_string_array (GDM_KEY_HALT);
-
- if (try_commands (s)) {
- /* maybe these don't run but oh well - there isn't
- really a good way to know a priori if the command
- will succeed. */
- gdm_final_cleanup ();
- VE_IGNORE_EINTR (g_chdir ("/"));
-#ifdef __linux__
- change_to_first_and_clear (FALSE);
-#endif /* __linux */
-
- }
-}
-
-static void
-restart_machine (void)
-{
- const char **s;
-
- g_debug (_("Restarting computer..."));
-
- s = gdm_daemon_config_get_value_string_array (GDM_KEY_REBOOT);
-
- if (try_commands (s)) {
- gdm_final_cleanup ();
- VE_IGNORE_EINTR (g_chdir ("/"));
-
-#ifdef __linux__
- change_to_first_and_clear (TRUE);
-#endif /* __linux */
-
- }
-}
-
-static void
-custom_cmd (long cmd_id)
-{
- gchar * key_string;
-
- if (cmd_id < 0 || cmd_id >= GDM_CUSTOM_COMMAND_MAX) {
- /* We are just feeling very paranoid */
- gdm_error (_("custom_cmd: Custom command index %ld outside permitted range [0,%d)"),
- cmd_id, GDM_CUSTOM_COMMAND_MAX);
- return;
- }
-
- key_string = g_strdup_printf ("%s%ld=", GDM_KEY_CUSTOM_CMD_NO_RESTART_TEMPLATE, cmd_id);
- if (gdm_daemon_config_get_value_bool (key_string))
- custom_cmd_no_restart (cmd_id);
- else
- custom_cmd_restart (cmd_id);
-
- g_free(key_string);
-}
-
-static void
-custom_cmd_restart (long cmd_id)
-{
- gchar * key_string;
- char **argv;
- const char *s;
-
- g_debug (_("Executing custom command %ld with restart option..."), cmd_id);
-
- gdm_final_cleanup ();
- VE_IGNORE_EINTR (g_chdir ("/"));
-
-#ifdef __linux__
- change_to_first_and_clear (TRUE);
-#endif /* __linux */
-
- key_string = g_strdup_printf ("%s%ld=", GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_id);
-
- argv = NULL;
- s = gdm_daemon_config_get_value_string (key_string);
- g_free (key_string);
- if (s != NULL) {
- g_shell_parse_argv (s, NULL, &argv, NULL);
- }
-
- if (argv != NULL && argv[0] != NULL)
- VE_IGNORE_EINTR (execv (argv[0], argv));
-
- g_strfreev (argv);
-
- gdm_error (_("%s: Execution of custom command failed: %s"),
- "gdm_child_action", strerror (errno));
-}
-
-static void
-custom_cmd_no_restart (long cmd_id)
-{
- pid_t pid;
-
- g_debug (_("Executing custom command %ld with no restart option ..."), cmd_id);
-
- pid = fork ();
-
- if (pid < 0) {
- /*failed fork*/
- gdm_error (_("custom_cmd: forking process for custom command %ld failed"), cmd_id);
- return;
- }
- else if (pid == 0) {
- /* child */
- char **argv;
- const char *s;
- gchar *key_string;
-
- key_string = g_strdup_printf ("%s%ld=", GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_id);
-
- argv = NULL;
- s = gdm_daemon_config_get_value_string (key_string);
- g_free (key_string);
- if (s != NULL) {
- g_shell_parse_argv (s, NULL, &argv, NULL);
- }
-
- if (argv != NULL && argv[0] != NULL)
- VE_IGNORE_EINTR (execv (argv[0], argv));
-
- g_strfreev (argv);
-
- gdm_error (_("%s: Execution of custom command failed: %s"),
- "gdm_child_action", strerror (errno));
- _exit (0);
- }
- else {
- /* parent */
- gint exitstatus = 0, status;
- pid_t p_stat = waitpid (1, &exitstatus, WNOHANG);
- if (p_stat > 0) {
- if G_LIKELY (WIFEXITED (exitstatus)){
- status = WEXITSTATUS (exitstatus);
- g_debug (_("custom_cmd: child %d returned %d"), p_stat, status);
- }
- return;
- }
- }
-}
-
-static gboolean
-gdm_cleanup_children (void)
-{
- pid_t pid;
- gint exitstatus = 0, status;
- GdmDisplay *d = NULL;
- gboolean crashed;
- gboolean sysmenu;
-
- /* Pid and exit status of slave that died */
- pid = waitpid (-1, &exitstatus, WNOHANG);
-
- if (pid <= 0)
- return FALSE;
-
- if G_LIKELY (WIFEXITED (exitstatus)) {
- status = WEXITSTATUS (exitstatus);
- crashed = FALSE;
- g_debug ("gdm_cleanup_children: child %d returned %d", pid, status);
- } else {
- status = EXIT_SUCCESS;
- crashed = TRUE;
- if (WIFSIGNALED (exitstatus)) {
- if (WTERMSIG (exitstatus) == SIGTERM ||
- WTERMSIG (exitstatus) == SIGINT) {
- /* we send these signals, sometimes children don't handle them */
- g_debug ("gdm_cleanup_children: child %d died of signal %d (TERM/INT)", pid,
- (int)WTERMSIG (exitstatus));
- } else {
- gdm_error ("gdm_cleanup_children: child %d crashed of signal %d", pid,
- (int)WTERMSIG (exitstatus));
- }
- } else {
- gdm_error ("gdm_cleanup_children: child %d crashed", pid);
- }
- }
-
- if (pid == extra_process) {
- /* an extra process died, yay! */
- extra_process = 0;
- extra_status = exitstatus;
- return TRUE;
- }
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (pid);
-
- if (d == NULL)
- return TRUE;
-
- /* whack connections about this display */
- if (unixconn != NULL)
- gdm_kill_subconnections_with_display (unixconn, d);
-
- if G_UNLIKELY (crashed) {
- gdm_error ("gdm_cleanup_children: Slave crashed, killing its "
- "children");
-
- if (d->sesspid > 1)
- kill (-(d->sesspid), SIGTERM);
- d->sesspid = 0;
- if (d->greetpid > 1)
- kill (-(d->greetpid), SIGTERM);
- d->greetpid = 0;
- if (d->chooserpid > 1)
- kill (-(d->chooserpid), SIGTERM);
- d->chooserpid = 0;
- if (d->servpid > 1)
- kill (d->servpid, SIGTERM);
- d->servpid = 0;
-
- if (gdm_daemon_config_get_value_bool (GDM_KEY_DYNAMIC_XSERVERS)) {
- /* XXX - This needs to be handled better */
- gdm_server_whack_lockfile (d);
- }
-
- /* race avoider */
- gdm_sleep_no_signal (1);
- }
-
- /* null all these, they are not valid most definately */
- d->servpid = 0;
- d->sesspid = 0;
- d->greetpid = 0;
- d->chooserpid = 0;
-
- /* definately not logged in now */
- d->logged_in = FALSE;
- g_free (d->login);
- d->login = NULL;
-
- /* Declare the display dead */
- d->slavepid = 0;
- d->dispstat = DISPLAY_DEAD;
-
- sysmenu = gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, d->name);
-
- if ( ! sysmenu &&
- (status == DISPLAY_RESTARTGDM ||
- status == DISPLAY_REBOOT ||
- status == DISPLAY_SUSPEND ||
- status == DISPLAY_HALT)) {
- gdm_info (_("Restart GDM, Restart machine, Suspend, or Halt request when there is no system menu from display %s"), d->name);
- status = DISPLAY_REMANAGE;
- }
-
- if ( ! d->attached &&
- (status == DISPLAY_RESTARTGDM ||
- status == DISPLAY_REBOOT ||
- status == DISPLAY_SUSPEND ||
- status == DISPLAY_HALT)) {
- gdm_info (_("Restart GDM, Restart machine, Suspend or Halt request from a non-static display %s"), d->name);
- status = DISPLAY_REMANAGE;
- }
-
- if (status == DISPLAY_RUN_CHOOSER) {
- /* use the chooser on the next run (but only if allowed) */
- if (sysmenu &&
- gdm_daemon_config_get_value_bool_per_display (GDM_KEY_CHOOSER_BUTTON, d->name))
- d->use_chooser = TRUE;
- status = DISPLAY_REMANAGE;
- /* go around the display loop detection, these are short
- * sessions, so this decreases the chances of the loop
- * detection being hit */
- d->last_loop_start_time = 0;
- }
-
- if (status == DISPLAY_CHOSEN) {
- /* forget about this indirect id, since this
- * display will be dead very soon, and we don't want it
- * to take the indirect display with it */
- d->indirect_id = 0;
- status = DISPLAY_REMANAGE;
- }
-
- if (status == DISPLAY_GREETERFAILED) {
- if (d->managetime + 10 >= time (NULL)) {
- d->try_different_greeter = TRUE;
- } else {
- d->try_different_greeter = FALSE;
- }
- /* now just remanage */
- status = DISPLAY_REMANAGE;
- } else {
- d->try_different_greeter = FALSE;
- }
-
- /* checkout if we can actually do stuff */
- switch (status) {
- case DISPLAY_REBOOT:
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_REBOOT) == NULL)
- status = DISPLAY_REMANAGE;
- break;
- case DISPLAY_HALT:
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_HALT) == NULL)
- status = DISPLAY_REMANAGE;
- break;
- case DISPLAY_SUSPEND:
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_SUSPEND) == NULL)
- status = DISPLAY_REMANAGE;
- break;
- default:
- break;
- }
-
- /* if we crashed clear the theme */
- if (crashed) {
- g_free (d->theme_name);
- d->theme_name = NULL;
- }
-
- start_autopsy:
-
- /* Autopsy */
- switch (status) {
-
- case DISPLAY_ABORT: /* Bury this display for good */
- gdm_info (_("%s: Aborting display %s"),
- "gdm_child_action", d->name);
-
- gdm_try_logout_action (d);
- gdm_safe_restart ();
-
- gdm_display_unmanage (d);
-
- /* If there are some pending statics, start them now */
- gdm_start_first_unborn_local (3 /* delay */);
- break;
-
- case DISPLAY_REBOOT: /* Restart machine */
- restart_machine ();
-
- status = DISPLAY_REMANAGE;
- goto start_autopsy;
- break;
-
- case DISPLAY_HALT: /* Halt machine */
- halt_machine ();
-
- status = DISPLAY_REMANAGE;
- goto start_autopsy;
- break;
-
- case DISPLAY_SUSPEND: /* Suspend machine */
- /* XXX: this is ugly, why should there be a suspend like this,
- * see GDM_SOP_SUSPEND_MACHINE */
- suspend_machine ();
-
- status = DISPLAY_REMANAGE;
- goto start_autopsy;
- break;
-
- case DISPLAY_RESTARTGDM:
- gdm_restart_now ();
- break;
-
- case DISPLAY_XFAILED: /* X sucks */
- g_debug ("X failed!");
- /* inform about error if needed */
- if (d->socket_conn != NULL) {
- GdmConnection *conn = d->socket_conn;
- d->socket_conn = NULL;
- gdm_connection_set_close_notify (conn, NULL, NULL);
- gdm_connection_write (conn, "ERROR 3 X failed\n");
- }
-
- gdm_try_logout_action (d);
- gdm_safe_restart ();
-
- /* in remote/flexi case just drop to _REMANAGE */
- if (d->type == TYPE_STATIC) {
- time_t now = time (NULL);
- d->x_faileds++;
- /* This really is likely the first time if it's been,
- some time, say 5 minutes */
- if (now - d->last_x_failed > (5*60)) {
- /* reset */
- d->x_faileds = 1;
- d->last_x_failed = now;
- /* well sleep at least 3 seconds before starting */
- d->sleep_before_run = 3;
- } else if (d->x_faileds >= 3) {
- g_debug ("gdm_child_action: dealing with X crashes");
- if ( ! deal_with_x_crashes (d)) {
- g_debug ("gdm_child_action: Aborting display");
- /* an original way to deal with these things:
- * "Screw you guys, I'm going home!" */
- gdm_display_unmanage (d);
-
- /* If there are some pending statics,
- * start them now */
- gdm_start_first_unborn_local (3 /* delay */);
- break;
- }
- g_debug ("gdm_child_action: Trying again");
-
- /* reset */
- d->x_faileds = 0;
- d->last_x_failed = 0;
- } else {
- /* well sleep at least 3 seconds before starting */
- d->sleep_before_run = 3;
- }
- /* go around the display loop detection, we're doing
- * our own here */
- d->last_loop_start_time = 0;
- }
- /* fall through */
-
- case DISPLAY_REMANAGE: /* Remanage display */
- default:
- g_debug ("gdm_child_action: In remanage");
-
- /* if we did REMANAGE, that means that we're no longer failing */
- if (status == DISPLAY_REMANAGE) {
- /* reset */
- d->x_faileds = 0;
- d->last_x_failed = 0;
- }
-
- /* inform about error if needed */
- if (d->socket_conn != NULL) {
- GdmConnection *conn = d->socket_conn;
- d->socket_conn = NULL;
- gdm_connection_set_close_notify (conn, NULL, NULL);
- gdm_connection_write (conn, "ERROR 2 Startup errors\n");
- }
-
- gdm_try_logout_action (d);
- gdm_safe_restart ();
-
- /* This is a static server so we start a new slave */
- if (d->type == TYPE_STATIC) {
- if ( ! gdm_display_manage (d)) {
- gdm_display_unmanage (d);
- /* If there are some pending statics,
- * start them now */
- gdm_start_first_unborn_local (3 /* delay */);
- }
- } else if (d->type == TYPE_FLEXI || d->type == TYPE_FLEXI_XNEST) {
- /* if this was a chooser session and we have chosen a host,
- then we don't want to unmanage, we want to manage and
- choose that host */
- if (d->chosen_hostname != NULL || d->use_chooser) {
- if ( ! gdm_display_manage (d)) {
- gdm_display_unmanage (d);
- }
- } else {
- /* else, this is a one time thing */
- gdm_display_unmanage (d);
- }
- /* Remote displays will send a request to be managed */
- } else /* TYPE_XDMCP */ {
- gdm_display_unmanage (d);
- }
-
- break;
- }
-
- gdm_try_logout_action (d);
- gdm_safe_restart ();
-
- return TRUE;
-}
-
-static void
-gdm_restart_now (void)
-{
- gdm_info (_("GDM restarting ..."));
- gdm_final_cleanup ();
- gdm_restoreenv ();
- VE_IGNORE_EINTR (execvp (stored_argv[0], stored_argv));
- gdm_error (_("Failed to restart self"));
- _exit (1);
-}
-
-static void
-gdm_safe_restart (void)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- if ( ! gdm_restart_mode)
- return;
-
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
-
- if (d->logged_in)
- return;
- }
-
- gdm_restart_now ();
-}
-
-static void
-gdm_do_logout_action (GdmLogoutAction logout_action)
-{
- switch (logout_action) {
- case GDM_LOGOUT_ACTION_HALT:
- halt_machine ();
- break;
-
- case GDM_LOGOUT_ACTION_REBOOT:
- restart_machine ();
- break;
-
- case GDM_LOGOUT_ACTION_SUSPEND:
- suspend_machine ();
- break;
-
- default:
- /* This is a bit ugly but its the only place we can
- check for the range of values */
- if (logout_action >= GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST &&
- logout_action <= GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST)
- custom_cmd (logout_action - GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST);
- break;
- }
-}
-
-static void
-gdm_try_logout_action (GdmDisplay *disp)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- if (disp != NULL &&
- disp->logout_action != GDM_LOGOUT_ACTION_NONE &&
- ! disp->logged_in) {
- gdm_do_logout_action (disp->logout_action);
- disp->logout_action = GDM_LOGOUT_ACTION_NONE;
- return;
- }
-
- if (safe_logout_action == GDM_LOGOUT_ACTION_NONE)
- return;
-
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
-
- if (d->logged_in)
- return;
- }
-
- gdm_do_logout_action (safe_logout_action);
- safe_logout_action = GDM_LOGOUT_ACTION_NONE;
-}
-
-static void
-main_daemon_abrt (int sig)
-{
- /* FIXME: note that this could mean out of memory */
- gdm_error (_("main daemon: Got SIGABRT. Something went very wrong. Going down!"));
- gdm_final_cleanup ();
- exit (EXIT_FAILURE);
-}
-
-static gboolean
-mainloop_sig_callback (int sig, gpointer data)
-{
- /* signals are at somewhat random times aren't they? */
- gdm_random_tick ();
-
- g_debug ("mainloop_sig_callback: Got signal %d", (int)sig);
- switch (sig)
- {
- case SIGCHLD:
- while (gdm_cleanup_children ())
- ;
- break;
-
- case SIGINT:
- case SIGTERM:
- g_debug ("mainloop_sig_callback: Got TERM/INT. Going down!");
- gdm_final_cleanup ();
- exit (EXIT_SUCCESS);
- break;
-
-#ifdef SIGXFSZ
- case SIGXFSZ:
- gdm_error ("main daemon: Hit file size rlimit, restarting!");
- gdm_restart_now ();
- break;
-#endif
-
-#ifdef SIGXCPU
- case SIGXCPU:
- gdm_error ("main daemon: Hit CPU rlimit, restarting!");
- gdm_restart_now ();
- break;
-#endif
-
- case SIGHUP:
- gdm_restart_now ();
- break;
-
- case SIGUSR1:
- gdm_restart_mode = TRUE;
- gdm_safe_restart ();
- break;
-
- default:
- break;
- }
-
- return TRUE;
-}
-
-/*
- * main: The main daemon control
- */
-
-static void
-store_argv (int argc, char *argv[])
-{
- int i;
-
- stored_argv = g_new0 (char *, argc + 1);
- for (i = 0; i < argc; i++)
- stored_argv[i] = g_strdup (argv[i]);
- stored_argv[i] = NULL;
- stored_argc = argc;
-}
-
-static void
-close_notify (gpointer data)
-{
- GdmConnection **conn = data;
- * conn = NULL;
-}
-
-static void
-create_connections (void)
-{
- int p[2];
- gchar *path;
-
- path = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), ".gdmfifo", NULL);
- fifoconn = gdm_connection_open_fifo (path, 0660);
- g_free (path);
-
- if G_LIKELY (fifoconn != NULL) {
- gdm_connection_set_handler (fifoconn,
- gdm_handle_message,
- NULL /* data */,
- NULL /* destroy_notify */);
- gdm_connection_set_close_notify (fifoconn,
- &fifoconn,
- close_notify);
- }
-
- if G_UNLIKELY (pipe (p) < 0) {
- slave_fifo_pipe_fd = -1;
- pipeconn = NULL;
- } else {
- slave_fifo_pipe_fd = p[1];
- pipeconn = gdm_connection_open_fd (p[0]);
- }
-
- if G_LIKELY (pipeconn != NULL) {
- gdm_connection_set_handler (pipeconn,
- gdm_handle_message,
- NULL /* data */,
- NULL /* destroy_notify */);
- gdm_connection_set_close_notify (pipeconn,
- &pipeconn,
- close_notify);
- } else {
- VE_IGNORE_EINTR (close (p[0]));
- VE_IGNORE_EINTR (close (p[1]));
- slave_fifo_pipe_fd = -1;
- }
-
- unixconn = gdm_connection_open_unix (GDM_SUP_SOCKET, 0666);
-
- if G_LIKELY (unixconn != NULL) {
- gdm_connection_set_handler (unixconn,
- gdm_handle_user_message,
- NULL /* data */,
- NULL /* destroy_notify */);
- gdm_connection_set_nonblock (unixconn, TRUE);
- gdm_connection_set_close_notify (unixconn,
- &unixconn,
- close_notify);
- }
-}
-
-static void
-calc_sqrt2 (void)
-{
- unsigned long n = 0, h = 0;
- double x;
- printf ("\n");
- for (;;) {
- x = g_random_double_range (1.0, 2.0);
- if (x*x <= 2.0)
- h++;
- n++;
- if ( ! (n & 0xfff)) {
- double sqrttwo = 1.0 + ((double)h)/(double)n;
- printf ("sqrt(2) ~~ %1.10f\t(1 + %lu/%lu) "
- "iteration: %lu \r",
- sqrttwo, h, n, n);
- }
- }
-}
-
-GOptionEntry options [] = {
- { "nodaemon", '\0', 0, G_OPTION_ARG_NONE,
- &no_daemon, N_("Do not fork into the background"), NULL },
- { "no-console", '\0', 0, G_OPTION_ARG_NONE,
- &no_console, N_("No console (static) servers to be run"), NULL },
- { "config", '\0', 0, G_OPTION_ARG_STRING,
- &config_file, N_("Alternative GDM System Defaults configuration file"), N_("CONFIGFILE") },
- { "preserve-ld-vars", '\0', 0, G_OPTION_ARG_NONE,
- &preserve_ld_vars, N_("Preserve LD_* variables"), NULL },
- { "version", '\0', 0, G_OPTION_ARG_NONE,
- &print_version, N_("Print GDM version"), NULL },
- { "wait-for-go", '\0', 0, G_OPTION_ARG_NONE,
- &gdm_wait_for_go, N_("Start the first X server but then halt until we get a GO in the fifo"), NULL },
- { "monte-carlo-sqrt2", 0, 0, G_OPTION_ARG_NONE,
- &monte_carlo_sqrt2, NULL, NULL },
- { NULL }
-};
-
-static gboolean
-linux_only_is_running (pid_t pid)
-{
- char resolved_self[PATH_MAX];
- char resolved_running[PATH_MAX];
-
- char *running = g_strdup_printf ("/proc/%lu/exe", (gulong)pid);
-
- if (realpath ("/proc/self/exe", resolved_self) == NULL) {
- g_free (running);
- /* probably not a linux system */
- return TRUE;
- }
-
- if (realpath (running, resolved_running) == NULL) {
- g_free (running);
- /* probably not a linux system */
- return TRUE;
- }
-
- g_free (running);
-
- if (strcmp (resolved_running, resolved_self) == 0)
- return TRUE;
- return FALSE;
-}
-
-static void
-ensure_desc_012 (void)
-{
- int fd;
- /* We here ensure descriptors 0, 1 and 2
- * we of course count on the fact that open
- * opens the lowest available descriptor */
- for (;;) {
- fd = gdm_open_dev_null (O_RDWR);
- /* Once we are up to 3, we're beyond stdin,
- * stdout and stderr */
- if (fd >= 3) {
- VE_IGNORE_EINTR (close (fd));
- break;
- }
- }
-}
-
-/* initially if we get a TERM or INT we just want to die,
- but we want to also kill an extra process if it exists */
-static void
-initial_term_int (int signal)
-{
- if (extra_process > 1)
- kill (-(extra_process), SIGTERM);
- _exit (EXIT_FAILURE);
-}
-
-static void
-gdm_make_global_cookie (void)
-{
- FILE *fp;
- char *file;
-
- gdm_cookie_generate ((char **)&gdm_global_cookie, (char **)&gdm_global_bcookie);
-
- file = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), ".cookie", NULL);
- VE_IGNORE_EINTR (g_unlink (file));
-
- fp = gdm_safe_fopen_w (file, 0600);
- if G_UNLIKELY (fp == NULL) {
- gdm_error (_("Can't open %s for writing"), file);
- g_free (file);
- return;
- }
-
- VE_IGNORE_EINTR (fprintf (fp, "%s\n", gdm_global_cookie));
-
- /* FIXME: What about out of disk space errors? */
- errno = 0;
- VE_IGNORE_EINTR (fclose (fp));
- if G_UNLIKELY (errno != 0) {
- gdm_error (_("Can't write to %s: %s"), file,
- strerror (errno));
- }
-
- g_free (file);
-}
-
-int
-main (int argc, char *argv[])
-{
- FILE *pf;
- sigset_t mask;
- struct sigaction sig, child, abrt;
- GOptionContext *ctx;
- const char *pidfile;
- int i;
-
- /* semi init pseudorandomness */
- gdm_random_tick ();
-
- /* We here ensure descriptors 0, 1 and 2 */
- ensure_desc_012 ();
-
- /* store all initial stuff, args, env, rlimits, runlevel */
- store_argv (argc, argv);
- gdm_saveenv ();
- gdm_get_initial_limits ();
-
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- textdomain (GETTEXT_PACKAGE);
-
- setlocale (LC_ALL, "");
-
- /* Initialize runtime environment */
- umask (022);
-
- g_type_init ();
-
- ctx = g_option_context_new (_("- The GNOME login manager"));
- g_option_context_add_main_entries (ctx, options, _("main options"));
-
- /* preprocess the arguments to support the xdm style -nodaemon
- * option
- */
- for (i = 0; i < argc; i++) {
- if (strcmp (argv[i], "-nodaemon") == 0)
- argv[i] = (char *) "--nodaemon";
- }
-
- g_option_context_parse (ctx, &argc, &argv, NULL);
- g_option_context_free (ctx);
-
- if (monte_carlo_sqrt2) {
- calc_sqrt2 ();
- return 0;
- }
-
- if (print_version) {
- printf ("GDM %s\n", VERSION);
- fflush (stdout);
- exit (0);
- }
-
- gdm_log_init ();
- /* Parse configuration file */
- gdm_daemon_config_parse (config_file, no_console);
- gdm_log_set_debug (gdm_daemon_config_get_bool_for_id (GDM_ID_DEBUG));
-
- /* XDM compliant error message */
- if G_UNLIKELY (getuid () != 0) {
- /* make sure the pid file doesn't get wiped */
- gdm_error (_("Only root wants to run GDM\n"));
- exit (-1);
- }
-
- main_loop = g_main_loop_new (NULL, FALSE);
-
- /* initial TERM/INT handler */
- sig.sa_handler = initial_term_int;
- sig.sa_flags = SA_RESTART;
- sigemptyset (&sig.sa_mask);
-
- /*
- * Do not call gdm_fail before calling gdm_config_parse ()
- * since the gdm_fail function uses config data
- */
- if G_UNLIKELY (sigaction (SIGTERM, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "TERM", strerror (errno));
-
- if G_UNLIKELY (sigaction (SIGINT, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "INT", strerror (errno));
-
- /* get the name of the root user */
- gdm_root_user ();
-
- pidfile = GDM_PID_FILE;
-
- /* Check if another gdm process is already running */
- if (g_access (pidfile, R_OK) == 0) {
-
- /* Check if the existing process is still alive. */
- gint pidv;
-
- pf = fopen (pidfile, "r");
-
- if (pf != NULL &&
- fscanf (pf, "%d", &pidv) == 1 &&
- kill (pidv, 0) == 0 &&
- linux_only_is_running (pidv)) {
- /* make sure the pid file doesn't get wiped */
- VE_IGNORE_EINTR (fclose (pf));
- gdm_fail (_("GDM already running. Aborting!"));
- }
-
- if (pf != NULL)
- VE_IGNORE_EINTR (fclose (pf));
- }
-
- /* Become daemon unless started in -nodaemon mode or child of init */
- if (no_daemon || getppid () == 1) {
-
- /* Write pid to pidfile */
- errno = 0;
- if ((pf = gdm_safe_fopen_w (pidfile, 0644)) != NULL) {
- errno = 0;
- VE_IGNORE_EINTR (fprintf (pf, "%d\n", (int)getpid ()));
- VE_IGNORE_EINTR (fclose (pf));
- if (errno != 0) {
- /* FIXME: how to handle this? */
- gdm_fdprintf (2, _("Cannot write PID file %s: possibly out of diskspace. Error: %s\n"),
- pidfile, strerror (errno));
- gdm_error (_("Cannot write PID file %s: possibly out of diskspace. Error: %s"),
- pidfile, strerror (errno));
-
- }
- } else if (errno != 0) {
- /* FIXME: how to handle this? */
- gdm_fdprintf (2, _("Cannot write PID file %s: possibly out of diskspace. Error: %s\n"),
- pidfile, strerror (errno));
- gdm_error (_("Cannot write PID file %s: possibly out of diskspace. Error: %s"),
- pidfile, strerror (errno));
-
- }
-
- VE_IGNORE_EINTR (g_chdir (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR)));
- umask (022);
- }
- else
- gdm_daemonify ();
-
-#ifdef __sun
- g_unlink (SDTLOGIN_DIR);
- g_mkdir (SDTLOGIN_DIR, 0700);
-#endif
-
- /* Signal handling */
- ve_signal_add (SIGCHLD, mainloop_sig_callback, NULL);
- ve_signal_add (SIGTERM, mainloop_sig_callback, NULL);
- ve_signal_add (SIGINT, mainloop_sig_callback, NULL);
- ve_signal_add (SIGHUP, mainloop_sig_callback, NULL);
- ve_signal_add (SIGUSR1, mainloop_sig_callback, NULL);
-
- sig.sa_handler = ve_signal_notify;
- sig.sa_flags = SA_RESTART;
- sigemptyset (&sig.sa_mask);
-
- if G_UNLIKELY (sigaction (SIGTERM, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "TERM", strerror (errno));
-
- if G_UNLIKELY (sigaction (SIGINT, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "INT", strerror (errno));
-
- if G_UNLIKELY (sigaction (SIGHUP, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "HUP", strerror (errno));
-
- if G_UNLIKELY (sigaction (SIGUSR1, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "USR1", strerror (errno));
-
- /* some process limit signals we catch and restart on,
- note that we don't catch these in the slave, but then
- we catch those in the main daemon as slave crashing
- (terminated by signal), and we clean up appropriately */
-#ifdef SIGXCPU
- ve_signal_add (SIGXCPU, mainloop_sig_callback, NULL);
- if G_UNLIKELY (sigaction (SIGXCPU, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "XCPU", strerror (errno));
-#endif
-#ifdef SIGXFSZ
- ve_signal_add (SIGXFSZ, mainloop_sig_callback, NULL);
- if G_UNLIKELY (sigaction (SIGXFSZ, &sig, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "XFSZ", strerror (errno));
-#endif
-
- /* cannot use mainloop for SIGABRT, the handler can never
- return */
- abrt.sa_handler = main_daemon_abrt;
- abrt.sa_flags = SA_RESTART;
- sigemptyset (&abrt.sa_mask);
-
- if G_UNLIKELY (sigaction (SIGABRT, &abrt, NULL) < 0)
- gdm_fail (_("%s: Error setting up %s signal handler: %s"),
- "main", "ABRT", strerror (errno));
-
- child.sa_handler = ve_signal_notify;
- child.sa_flags = SA_RESTART|SA_NOCLDSTOP;
- sigemptyset (&child.sa_mask);
- sigaddset (&child.sa_mask, SIGCHLD);
-
- if G_UNLIKELY (sigaction (SIGCHLD, &child, NULL) < 0)
- gdm_fail (_("%s: Error setting up CHLD signal handler"), "gdm_main");
-
- sigemptyset (&mask);
- sigaddset (&mask, SIGINT);
- sigaddset (&mask, SIGTERM);
- sigaddset (&mask, SIGCHLD);
- sigaddset (&mask, SIGHUP);
- sigaddset (&mask, SIGUSR1);
- sigaddset (&mask, SIGABRT);
-#ifdef SIGXCPU
- sigaddset (&mask, SIGXCPU);
-#endif
-#ifdef SIGXFSZ
- sigaddset (&mask, SIGXFSZ);
-#endif
- sigprocmask (SIG_UNBLOCK, &mask, NULL);
-
- gdm_signal_ignore (SIGUSR2);
- gdm_signal_ignore (SIGPIPE);
-
- /* ignore power failures, up to user processes to
- * handle things correctly */
-#ifdef SIGPWR
- gdm_signal_ignore (SIGPWR);
-#endif
- /* can we ever even get this one? */
-#ifdef SIGLOST
- gdm_signal_ignore (SIGLOST);
-#endif
-
- g_debug ("gdm_main: Here we go...");
-
-#ifdef HAVE_LOGINDEVPERM
- di_devperm_login ("/dev/console", gdm_daemon_config_get_gdmuid (), gdm_daemon_config_get_gdmgid (), NULL);
-#endif /* HAVE_LOGINDEVPERM */
-
- /* Init XDMCP if applicable */
- if (gdm_daemon_config_get_value_bool (GDM_KEY_XDMCP) && ! gdm_wait_for_go) {
- gdm_xdmcp_init ();
- }
-
- create_connections ();
-
- /* make sure things (currently /tmp/.ICE-unix and /tmp/.X11-unix)
- * are sane */
- gdm_ensure_sanity () ;
-
- /* Make us a unique global cookie to authenticate */
- gdm_make_global_cookie ();
-
- /* Start static X servers */
- gdm_start_first_unborn_local (0 /* delay */);
-
- /* Accept remote connections */
- if (gdm_daemon_config_get_value_bool (GDM_KEY_XDMCP) && ! gdm_wait_for_go) {
- g_debug ("Accepting XDMCP connections...");
- gdm_xdmcp_run ();
- }
-
- /* We always exit via exit (), and sadly we need to g_main_quit ()
- * at times not knowing if it's this main or a recursive one we're
- * quitting.
- */
- while (1)
- {
- g_main_loop_run (main_loop);
- g_debug ("main: Exited main loop");
- }
-
- return EXIT_SUCCESS; /* Not reached */
-}
-
-static gboolean
-order_exists (int order)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (d->x_servers_order == order)
- return TRUE;
- }
- return FALSE;
-}
-
-static int
-get_new_order (GdmDisplay *d)
-{
- int order;
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- /* first try the position in the 'displays' list as
- * our order */
- for (order = 0, li = displays; li != NULL; order++, li = li->next) {
- if (li->data == d)
- break;
- }
- /* next make sure it's unique */
- while (order_exists (order))
- order++;
- return order;
-}
-
-static void
-write_x_servers (GdmDisplay *d)
-{
- FILE *fp;
- char *file = gdm_make_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR), d->name, ".Xservers");
- int i;
- int bogusname;
-
- if (d->x_servers_order < 0)
- d->x_servers_order = get_new_order (d);
-
- fp = gdm_safe_fopen_w (file, 0644);
- if G_UNLIKELY (fp == NULL) {
- gdm_error (_("Can't open %s for writing"), file);
- g_free (file);
- return;
- }
-
- for (bogusname = 0, i = 0; i < d->x_servers_order; bogusname++, i++) {
- char buf[32];
- g_snprintf (buf, sizeof (buf), ":%d", bogusname);
- if (strcmp (buf, d->name) == 0)
- g_snprintf (buf, sizeof (buf), ":%d", ++bogusname);
- VE_IGNORE_EINTR (fprintf (fp, "%s local /usr/X11R6/bin/Xbogus\n", buf));
- }
-
- if (SERVER_IS_LOCAL (d)) {
- char **argv;
- char *command;
- int argc;
- argc = 0;
- argv = NULL;
- gdm_server_resolve_command_line (d,
- FALSE, /* resolve_flags */
- NULL, /* vtarg */
- &argc,
- &argv);
- command = g_strjoinv (" ", argv);
- g_strfreev (argv);
- VE_IGNORE_EINTR (fprintf (fp, "%s local %s\n", d->name, command));
- g_free (command);
- } else {
- VE_IGNORE_EINTR (fprintf (fp, "%s foreign\n", d->name));
- }
-
- /* FIXME: What about out of disk space errors? */
- errno = 0;
- VE_IGNORE_EINTR (fclose (fp));
- if G_UNLIKELY (errno != 0) {
- gdm_error (_("Can't write to %s: %s"), file,
- strerror (errno));
- }
-
- g_free (file);
-}
-
-static void
-send_slave_ack_dialog_int (GdmDisplay *d, int type, int response)
-{
- if (d->master_notify_fd >= 0) {
- char *not;
-
- not = g_strdup_printf ("%c%c%d\n", GDM_SLAVE_NOTIFY_RESPONSE, type, response);
- VE_IGNORE_EINTR (write (d->master_notify_fd, not, strlen (not)));
-
- g_free (not);
- }
- if (d->slavepid > 1) {
- /* now yield the CPU as the other process has more
- useful work to do then we do */
-#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
- sched_yield ();
-#endif
- }
-}
-
-static void
-send_slave_ack_dialog_char (GdmDisplay *d, int type, const char *resp)
-{
- if (d->master_notify_fd >= 0) {
- if (resp == NULL) {
- char not[3];
-
- not[0] = GDM_SLAVE_NOTIFY_RESPONSE;
- not[1] = type;
- not[2] = '\n';
- VE_IGNORE_EINTR (write (d->master_notify_fd, not, 3));
- } else {
- char *not = g_strdup_printf ("%c%c%s\n",
- GDM_SLAVE_NOTIFY_RESPONSE,
- type,
- resp);
- VE_IGNORE_EINTR (write (d->master_notify_fd, not, strlen (not)));
- g_free (not);
- }
- }
- if (d->slavepid > 1) {
- /* now yield the CPU as the other process has more
- useful work to do then we do */
-#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
- sched_yield ();
-#endif
- }
-}
-
-static void
-send_slave_ack (GdmDisplay *d, const char *resp)
-{
- if (d->master_notify_fd >= 0) {
- if (resp == NULL) {
- char not[2];
- not[0] = GDM_SLAVE_NOTIFY_ACK;
- not[1] = '\n';
- VE_IGNORE_EINTR (write (d->master_notify_fd, not, 2));
- } else {
- char *not = g_strdup_printf ("%c%s\n",
- GDM_SLAVE_NOTIFY_ACK,
- resp);
- VE_IGNORE_EINTR (write (d->master_notify_fd, not, strlen (not)));
- g_free (not);
- }
- }
- if (d->slavepid > 1) {
- kill (d->slavepid, SIGUSR2);
- /* now yield the CPU as the other process has more
- useful work to do then we do */
-#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
- sched_yield ();
-#endif
- }
-}
-
-static void
-send_slave_command (GdmDisplay *d, const char *command)
-{
- if (d->master_notify_fd >= 0) {
- char *cmd = g_strdup_printf ("%c%s\n",
- GDM_SLAVE_NOTIFY_COMMAND,
- command);
- VE_IGNORE_EINTR (write (d->master_notify_fd, cmd, strlen (cmd)));
- g_free (cmd);
- }
- if (d->slavepid > 1) {
- kill (d->slavepid, SIGUSR2);
- /* now yield the CPU as the other process has more
- useful work to do then we do */
-#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
- sched_yield ();
-#endif
- }
-}
-
-static void
-gdm_handle_message (GdmConnection *conn, const char *msg, gpointer data)
-{
- /* Evil!, all this for debugging? */
- if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG)) {
- if (strncmp (msg, GDM_SOP_COOKIE " ",
- strlen (GDM_SOP_COOKIE " ")) == 0) {
- char *s = g_strndup
- (msg, strlen (GDM_SOP_COOKIE " XXXX XX"));
- /* cut off most of the cookie for "security" */
- g_debug ("Handling message: '%s...'", s);
- g_free (s);
- } else if (strncmp (msg, GDM_SOP_SYSLOG " ",
- strlen (GDM_SOP_SYSLOG " ")) != 0) {
- /* Don't print out the syslog message as it will
- * be printed out anyway as that's the whole point
- * of the message. */
- g_debug ("Handling message: '%s'", msg);
- }
- }
-
- if (strncmp (msg, GDM_SOP_CHOSEN " ",
- strlen (GDM_SOP_CHOSEN " ")) == 0) {
- gdm_choose_data (msg);
- } else if (strncmp (msg, GDM_SOP_CHOSEN_LOCAL " ",
- strlen (GDM_SOP_CHOSEN_LOCAL " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
-
- if (sscanf (msg, GDM_SOP_CHOSEN_LOCAL " %ld", &slave_pid)
- != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->chosen_hostname);
- d->chosen_hostname = g_strdup (p);
- g_debug ("Got CHOSEN_LOCAL == %s", p);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_XPID " ",
- strlen (GDM_SOP_XPID " ")) == 0) {
- GdmDisplay *d;
- long slave_pid, pid;
-
- if (sscanf (msg, GDM_SOP_XPID " %ld %ld", &slave_pid, &pid)
- != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->servpid = pid;
- g_debug ("Got XPID == %ld", (long)pid);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_SESSPID " ",
- strlen (GDM_SOP_SESSPID " ")) == 0) {
- GdmDisplay *d;
- long slave_pid, pid;
-
- if (sscanf (msg, GDM_SOP_SESSPID " %ld %ld", &slave_pid, &pid)
- != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->sesspid = pid;
- g_debug ("Got SESSPID == %ld", (long)pid);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_GREETPID " ",
- strlen (GDM_SOP_GREETPID " ")) == 0) {
- GdmDisplay *d;
- long slave_pid, pid;
-
- if (sscanf (msg, GDM_SOP_GREETPID " %ld %ld", &slave_pid, &pid)
- != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->greetpid = pid;
- g_debug ("Got GREETPID == %ld", (long)pid);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_CHOOSERPID " ",
- strlen (GDM_SOP_CHOOSERPID " ")) == 0) {
- GdmDisplay *d;
- long slave_pid, pid;
-
- if (sscanf (msg, GDM_SOP_CHOOSERPID " %ld %ld",
- &slave_pid, &pid) != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->chooserpid = pid;
- g_debug ("Got CHOOSERPID == %ld", (long)pid);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_LOGGED_IN " ",
- strlen (GDM_SOP_LOGGED_IN " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- int logged_in;
- if (sscanf (msg, GDM_SOP_LOGGED_IN " %ld %d", &slave_pid,
- &logged_in) != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->logged_in = logged_in ? TRUE : FALSE;
- g_debug ("Got logged in == %s",
- d->logged_in ? "TRUE" : "FALSE");
-
- /* whack connections about this display if a user
- * just logged out since we don't want such
- * connections persisting to be authenticated */
- if ( ! logged_in && unixconn != NULL)
- gdm_kill_subconnections_with_display (unixconn, d);
-
- /* if the user just logged out,
- * let's see if it's safe to restart */
- if ( ! d->logged_in) {
- gdm_try_logout_action (d);
- gdm_safe_restart ();
- }
-
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_DISP_NUM " ",
- strlen (GDM_SOP_DISP_NUM " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- int disp_num;
-
- if (sscanf (msg, GDM_SOP_DISP_NUM " %ld %d",
- &slave_pid, &disp_num) != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->name);
- d->name = g_strdup_printf (":%d", disp_num);
- d->dispnum = disp_num;
- g_debug ("Got DISP_NUM == %d", disp_num);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_VT_NUM " ",
- strlen (GDM_SOP_VT_NUM " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- int vt_num;
-
- if (sscanf (msg, GDM_SOP_VT_NUM " %ld %d",
- &slave_pid, &vt_num) != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- d->vt = vt_num;
- g_debug ("Got VT_NUM == %d", vt_num);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_LOGIN " ",
- strlen (GDM_SOP_LOGIN " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
-
- if (sscanf (msg, GDM_SOP_LOGIN " %ld",
- &slave_pid) != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
-
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->login);
- d->login = g_strdup (p);
- g_debug ("Got LOGIN == %s", p);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_QUERYLOGIN " ",
- strlen (GDM_SOP_QUERYLOGIN " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
-
- if (sscanf (msg, GDM_SOP_QUERYLOGIN " %ld",
- &slave_pid) != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
-
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- GString *resp = NULL;
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- g_debug ("Got QUERYLOGIN %s", p);
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *di = li->data;
- if (di->logged_in &&
- di->login != NULL &&
- strcmp (di->login, p) == 0) {
- gboolean migratable = FALSE;
-
- if (resp == NULL)
- resp = g_string_new (NULL);
- else
- resp = g_string_append_c (resp, ',');
-
- g_string_append (resp, di->name);
- g_string_append_c (resp, ',');
-
- if (d->attached && di->attached && di->vt > 0)
- migratable = TRUE;
- else if (gdm_daemon_config_get_value_string (GDM_KEY_XDMCP_PROXY_RECONNECT) != NULL &&
- d->type == TYPE_XDMCP_PROXY && di->type == TYPE_XDMCP_PROXY)
- migratable = TRUE;
-
- g_string_append_c (resp, migratable ? '1' : '0');
- }
- }
-
- /* send ack */
- if (resp != NULL) {
- send_slave_ack (d, resp->str);
- g_string_free (resp, TRUE);
- } else {
- send_slave_ack (d, NULL);
- }
- }
- } else if (strncmp (msg, GDM_SOP_MIGRATE " ",
- strlen (GDM_SOP_MIGRATE " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- if (sscanf (msg, GDM_SOP_MIGRATE " %ld", &slave_pid) != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
-
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
- if (d == NULL)
- return;
-
- g_debug ("Got MIGRATE %s", p);
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *di = li->data;
- if (di->logged_in && strcmp (di->name, p) == 0) {
- if (d->attached && di->vt > 0)
- gdm_change_vt (di->vt);
- else if (d->type == TYPE_XDMCP_PROXY && di->type == TYPE_XDMCP_PROXY)
- gdm_xdmcp_migrate (d, di);
- }
- }
- send_slave_ack (d, NULL);
- } else if (strncmp (msg, GDM_SOP_COOKIE " ",
- strlen (GDM_SOP_COOKIE " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
-
- if (sscanf (msg, GDM_SOP_COOKIE " %ld",
- &slave_pid) != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
-
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->cookie);
- d->cookie = g_strdup (p);
- g_debug ("Got COOKIE == <secret>");
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_AUTHFILE " ",
- strlen (GDM_SOP_AUTHFILE " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- char *p;
-
- if (sscanf (msg, GDM_SOP_AUTHFILE " %ld",
- &slave_pid) != 1)
- return;
- p = strchr (msg, ' ');
- if (p != NULL)
- p = strchr (p+1, ' ');
- if (p == NULL)
- return;
-
- p++;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->authfile);
- d->authfile = g_strdup (p);
- g_debug ("Got AUTHFILE == %s", d->authfile);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_FLEXI_ERR " ",
- strlen (GDM_SOP_FLEXI_ERR " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- int err;
-
- if (sscanf (msg, GDM_SOP_FLEXI_ERR " %ld %d",
- &slave_pid, &err) != 2)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- char *error = NULL;
- GdmConnection *conn = d->socket_conn;
- d->socket_conn = NULL;
-
- if (conn != NULL)
- gdm_connection_set_close_notify (conn,
- NULL, NULL);
-
- if (err == 3)
- error = "ERROR 3 X failed\n";
- else if (err == 4)
- error = "ERROR 4 X too busy\n";
- else if (err == 5)
- error = "ERROR 5 Nested display can't connect\n";
- else
- error = "ERROR 999 Unknown error\n";
- if (conn != NULL)
- gdm_connection_write (conn, error);
-
- g_debug ("Got FLEXI_ERR == %d", err);
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_FLEXI_OK " ",
- strlen (GDM_SOP_FLEXI_OK " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
-
- if (sscanf (msg, GDM_SOP_FLEXI_OK " %ld",
- &slave_pid) != 1)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- GdmConnection *conn = d->socket_conn;
- d->socket_conn = NULL;
-
- if (conn != NULL) {
- gdm_connection_set_close_notify (conn,
- NULL, NULL);
- if ( ! gdm_connection_printf (conn, "OK %s\n", d->name))
- gdm_display_unmanage (d);
- }
-
- g_debug ("Got FLEXI_OK");
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strcmp (msg, GDM_SOP_SOFT_RESTART) == 0) {
- gdm_restart_mode = TRUE;
- gdm_safe_restart ();
- } else if (strcmp (msg, GDM_SOP_DIRTY_SERVERS) == 0) {
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- send_slave_command (d, GDM_NOTIFY_DIRTY_SERVERS);
- }
- } else if (strcmp (msg, GDM_SOP_SOFT_RESTART_SERVERS) == 0) {
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- send_slave_command (d, GDM_NOTIFY_SOFT_RESTART_SERVERS);
- }
- } else if (strncmp (msg, GDM_SOP_SYSLOG " ",
- strlen (GDM_SOP_SYSLOG " ")) == 0) {
- char *p;
- long pid;
- int type;
- p = strchr (msg, ' ');
- if (p == NULL)
- return;
- p++;
- if (sscanf (p, "%ld", &pid) != 1)
- return;
- p = strchr (p, ' ');
- if (p == NULL)
- return;
- p++;
- if (sscanf (p, "%d", &type) != 1)
- return;
-
- p = strchr (p, ' ');
- if (p == NULL)
- return;
- p++;
-
- /* FIXME: use g_critical or g_debug when required */
- g_warning ("(child %ld) %s", pid, p);
- } else if (strcmp (msg, GDM_SOP_START_NEXT_LOCAL) == 0) {
- gdm_start_first_unborn_local (3 /* delay */);
- } else if (strcmp (msg, GDM_SOP_HUP_ALL_GREETERS) == 0) {
- /* probably shouldn't be done too often */
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- if (d->greetpid > 1)
- kill (d->greetpid, SIGHUP);
- else if (d->chooserpid > 1)
- kill (d->chooserpid, SIGHUP);
- }
- } else if (strcmp (msg, GDM_SOP_GO) == 0) {
- GSList *li;
- gboolean old_wait = gdm_wait_for_go;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
- gdm_wait_for_go = FALSE;
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *d = li->data;
- send_slave_command (d, GDM_NOTIFY_GO);
- }
- /* Init XDMCP if applicable */
- if (old_wait && gdm_daemon_config_get_value_bool (GDM_KEY_XDMCP)) {
- if (gdm_xdmcp_init ()) {
- g_debug ("Accepting XDMCP connections...");
- gdm_xdmcp_run ();
- }
- }
- } else if (strncmp (msg, GDM_SOP_WRITE_X_SERVERS " ",
- strlen (GDM_SOP_WRITE_X_SERVERS " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
-
- if (sscanf (msg, GDM_SOP_WRITE_X_SERVERS " %ld",
- &slave_pid) != 1)
- return;
-
- /* Find out who this slave belongs to */
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- write_x_servers (d);
-
- /* send ack */
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_SUSPEND_MACHINE " ",
- strlen (GDM_SOP_SUSPEND_MACHINE " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- gboolean sysmenu;
-
- if (sscanf (msg, GDM_SOP_SUSPEND_MACHINE " %ld", &slave_pid) != 1)
- return;
- d = gdm_display_lookup (slave_pid);
-
- gdm_info (_("Master suspending..."));
-
- sysmenu = gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, d->name);
- if (sysmenu && gdm_daemon_config_get_value_string (GDM_KEY_SUSPEND) != NULL) {
- suspend_machine ();
- }
- } else if (strncmp (msg, GDM_SOP_CHOSEN_THEME " ",
- strlen (GDM_SOP_CHOSEN_THEME " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- const char *p;
-
- if (sscanf (msg, GDM_SOP_CHOSEN_THEME " %ld", &slave_pid) != 1)
- return;
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- g_free (d->theme_name);
- d->theme_name = NULL;
-
- /* Syntax errors are partially OK here, if there
- was no theme argument we just wanted to clear the
- theme field */
- p = strchr (msg, ' ');
- if (p != NULL) {
- p = strchr (p+1, ' ');
- if (p != NULL) {
- while (*p == ' ')
- p++;
- if ( ! ve_string_empty (p))
- d->theme_name = g_strdup (p);
- }
- }
-
- send_slave_ack (d, NULL);
- }
- } else if (strncmp (msg, GDM_SOP_CUSTOM_CMD " ",
- strlen (GDM_SOP_CUSTOM_CMD " ")) == 0) {
- GdmDisplay *d;
- long slave_pid;
- long cmd_id;
-
- if (sscanf (msg, GDM_SOP_CUSTOM_CMD " %ld %ld", &slave_pid, &cmd_id) != 2)
- return;
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- custom_cmd (cmd_id);
- send_slave_ack (d, NULL);
- }
- } else if (strcmp (msg, GDM_SOP_FLEXI_XSERVER) == 0) {
- handle_flexi_server (NULL, TYPE_FLEXI, gdm_daemon_config_get_value_string (GDM_KEY_STANDARD_XSERVER),
- TRUE /* handled */,
- FALSE /* chooser */,
- NULL, 0, NULL, NULL, NULL);
- } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_ERROR_DIALOG,
- strlen ("opcode="GDM_SOP_SHOW_ERROR_DIALOG)) == 0) {
- GdmDisplay *d;
- GtkMessageType type;
- char **list;
- char *ptr;
- char *error;
- char *details_label;
- char *details_file;
- long slave_pid;
- int uid, gid;
-
- list = g_strsplit (msg, "$$", -1);
-
- ptr = strchr (list[1], '=');
- slave_pid = atol (ptr + 1);
-
- ptr = strchr (list[2], '=');
- type = atoi (ptr + 1);
-
- ptr = strchr (list[3], '=');
- error = g_malloc0 (strlen (ptr));
- strcpy (error, ptr + 1);
-
- ptr = strchr (list[4], '=');
- details_label = g_malloc0 (strlen (ptr));
- strcpy (details_label, ptr + 1);
-
- ptr = strchr (list[5], '=');
- details_file = g_malloc0 (strlen (ptr));
- strcpy (details_file, ptr + 1);
-
- ptr = strchr (list[6], '=');
- uid = atoi (ptr + 1);
-
- ptr = strchr (list[7], '=');
- gid = atoi (ptr + 1);
-
- d = gdm_display_lookup (slave_pid);
-
- if (d != NULL) {
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0644));
- }
-
- /* FIXME: this is really bad */
- gdm_errorgui_error_box_full (d, type, error, details_label, details_file, 0, 0);
-
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0640));
- }
-
- send_slave_ack_dialog_char (d, GDM_SLAVE_NOTIFY_ERROR_RESPONSE, NULL);
- }
-
- g_free (error);
- g_free (details_label);
- g_free (details_file);
- g_strfreev (list);
- } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_YESNO_DIALOG,
- strlen ("opcode="GDM_SOP_SHOW_YESNO_DIALOG)) == 0) {
- GdmDisplay *d;
- char **list;
- char *ptr;
- char *yesno_msg;
- long slave_pid;
- gboolean response_yesno;
-
- list = g_strsplit (msg, "$$", -1);
-
- ptr = strchr (list [1], '=');
- slave_pid = atol (ptr + 1);
-
- ptr = strchr (list [2], '=');
- yesno_msg = g_malloc0 (strlen (ptr));
- strcpy (yesno_msg, ptr + 1);
-
- d = gdm_display_lookup (slave_pid);
- if (d != NULL) {
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0644));
- }
-
- response_yesno = gdm_errorgui_failsafe_yesno (d, yesno_msg);
-
- send_slave_ack_dialog_int (d, GDM_SLAVE_NOTIFY_YESNO_RESPONSE, response_yesno);
-
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0640));
- }
- }
-
- g_free (yesno_msg);
- g_strfreev (list);
- } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_QUESTION_DIALOG,
- strlen ("opcode="GDM_SOP_SHOW_QUESTION_DIALOG)) == 0) {
- GdmDisplay *d;
- char **list;
- char *ptr;
- char *question_msg;
- char *response_question;
- long slave_pid;
- gboolean echo;
-
- list = g_strsplit (msg, "$$", -1);
-
- ptr = strchr (list [1], '=');
- slave_pid = atol (ptr + 1);
-
- ptr = strchr (list [2], '=');
- question_msg = g_malloc0 (strlen (ptr));
- strcpy (question_msg, ptr + 1);
-
- ptr = strchr (list [3], '=');
- echo = atoi (ptr + 1);
-
- d = gdm_display_lookup (slave_pid);
- if (d != NULL) {
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0644));
- }
-
- response_question = gdm_errorgui_failsafe_question (d, question_msg, echo);
-
- send_slave_ack_dialog_char (d, GDM_SLAVE_NOTIFY_QUESTION_RESPONSE, response_question);
-
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0640));
- }
- }
-
- g_free (question_msg);
- g_strfreev (list);
- } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_ASKBUTTONS_DIALOG,
- strlen ("opcode="GDM_SOP_SHOW_ASKBUTTONS_DIALOG)) == 0) {
- GdmDisplay *d;
- char *askbuttons_msg;
- char **list;
- char *ptr;
- char *options[4];
- long slave_pid;
- int i;
- int response_askbuttons;
-
- list = g_strsplit (msg, "$$", -1);
-
- ptr = strchr (list [1], '=');
- slave_pid = atol (ptr + 1);
-
- ptr = strchr (list [2], '=');
- askbuttons_msg = g_malloc0 (strlen (ptr));
- strcpy (askbuttons_msg, ptr + 1);
-
- ptr = strchr (list [3], '=');
- options[0] = g_malloc0 (strlen (ptr));
- strcpy (options[0], ptr + 1);
-
- ptr = strchr (list [4], '=');
- options[1] = g_malloc0 (strlen (ptr));
- strcpy (options[1], ptr + 1);
-
- ptr = strchr (list [5], '=');
- options[2] = g_malloc0 (strlen (ptr));
- strcpy (options[2], ptr + 1);
-
- ptr = strchr (list [6], '=');
- options[3] = g_malloc0 (strlen (ptr));
- strcpy (options[3], ptr + 1);
-
- d = gdm_display_lookup (slave_pid);
- if (d != NULL) {
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0644));
- }
-
- response_askbuttons = gdm_errorgui_failsafe_ask_buttons (d, askbuttons_msg, options);
-
- send_slave_ack_dialog_int (d, GDM_SLAVE_NOTIFY_ASKBUTTONS_RESPONSE, response_askbuttons);
- if (GDM_AUTHFILE (d)) {
- VE_IGNORE_EINTR (chmod (GDM_AUTHFILE (d), 0640));
- }
- }
-
- g_free (askbuttons_msg);
-
- for (i = 0; i < 3; i ++)
- g_free (options[i]);
- g_strfreev (list);
- }
-}
-
-/* extract second word and the rest of the string */
-static void
-extract_dispname_uid_xauthfile_cookie (const char *msg,
- char **dispname,
- uid_t *uid,
- char **xauthfile,
- char **cookie)
-{
- const char *p;
- int i;
- char *pp;
-
- *dispname = NULL;
- *xauthfile = NULL;
- *cookie = NULL;
-
- /* Get dispname */
- p = strchr (msg, ' ');
- if (p == NULL)
- return;
-
- while (*p == ' ')
- p++;
-
- *dispname = g_strdup (p);
- pp = strchr (*dispname, ' ');
- if (pp != NULL)
- *pp = '\0';
-
- /* Get uid */
- p = strchr (p, ' ');
- if (p == NULL) {
- *dispname = NULL;
- g_free (*dispname);
- return;
- }
- while (*p == ' ')
- p++;
-
- if (sscanf (p, "%d", &i) != 1) {
- *dispname = NULL;
- g_free (*dispname);
- return;
- }
- *uid = i;
-
- /* Get cookie */
- p = strchr (p, ' ');
- if (p == NULL) {
- *dispname = NULL;
- g_free (*dispname);
- return;
- }
- while (*p == ' ')
- p++;
-
- *cookie = g_strdup (p);
- pp = strchr (*cookie, ' ');
- if (pp != NULL)
- *pp = '\0';
-
- /* Get xauthfile */
- p = strchr (p, ' ');
- if (p == NULL) {
- *cookie = NULL;
- g_free (*cookie);
- *dispname = NULL;
- g_free (*dispname);
- return;
- }
-
- while (*p == ' ')
- p++;
-
- *xauthfile = g_strstrip (g_strdup (p));
-
-}
-
-static void
-close_conn (gpointer data)
-{
- GdmDisplay *disp = data;
-
- /* We still weren't finished, so we want to whack this display */
- if (disp->socket_conn != NULL) {
- disp->socket_conn = NULL;
- gdm_display_unmanage (disp);
- }
-}
-
-static GdmDisplay *
-find_display (const char *name)
-{
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (disp->name != NULL &&
- strcmp (disp->name, name) == 0)
- return disp;
- }
- return NULL;
-}
-
-static char *
-extract_dispnum (const char *addy)
-{
- int num;
- char *p;
-
- gdm_assert (addy != NULL);
-
- p = strchr (addy, ':');
- if (p == NULL)
- return NULL;
-
- /* Whee! handles DECnet even if we don't do that */
- while (*p == ':')
- p++;
-
- if (sscanf (p, "%d", &num) != 1)
- return NULL;
-
- return g_strdup_printf ("%d", num);
-}
-
-static char *
-dehex_cookie (const char *cookie, int *len)
-{
- /* it should be +1 really, but I'm paranoid */
- char *bcookie = g_new0 (char, (strlen (cookie) / 2) + 2);
- int i;
- const char *p;
-
- *len = 0;
-
- for (i = 0, p = cookie;
- *p != '\0' && *(p+1) != '\0';
- i++, p += 2) {
- unsigned int num;
- if (sscanf (p, "%02x", &num) != 1) {
- g_free (bcookie);
- return NULL;
- }
- bcookie[i] = num;
- }
- *len = i;
- return bcookie;
-}
-
-/* This runs as the user who owns the file */
-static gboolean
-check_cookie (const gchar *file, const gchar *disp, const gchar *cookie)
-{
- Xauth *xa;
- gchar *number;
- gchar *bcookie;
- int cookielen;
- gboolean ret = FALSE;
- int cnt = 0;
-
- FILE *fp = fopen (file, "r");
- if (fp == NULL)
- return FALSE;
-
- number = extract_dispnum (disp);
- if (number == NULL)
- return FALSE;
- bcookie = dehex_cookie (cookie, &cookielen);
- if (bcookie == NULL) {
- g_free (number);
- return FALSE;
- }
-
- while ((xa = XauReadAuth (fp)) != NULL) {
- if (xa->number_length == strlen (number) &&
- strncmp (xa->number, number, xa->number_length) == 0 &&
- xa->name_length == strlen ("MIT-MAGIC-COOKIE-1") &&
- strncmp (xa->name, "MIT-MAGIC-COOKIE-1",
- xa->name_length) == 0 &&
- xa->data_length == cookielen &&
- memcmp (xa->data, bcookie, cookielen) == 0) {
- XauDisposeAuth (xa);
- ret = TRUE;
- break;
- }
- XauDisposeAuth (xa);
-
- /* just being ultra anal */
- cnt++;
- if (cnt > 500)
- break;
- }
-
- g_free (number);
- g_free (bcookie);
-
- VE_IGNORE_EINTR (fclose (fp));
-
- return ret;
-}
-
-static void
-handle_flexi_server (GdmConnection *conn,
- int type,
- const char *server,
- gboolean handled,
- gboolean chooser,
- const char *xnest_disp,
- uid_t xnest_uid,
- const char *xnest_auth_file,
- const char *xnest_cookie,
- const char *username)
-{
- GdmDisplay *display;
- gchar *bin;
- uid_t server_uid = 0;
-
- g_debug ("flexi server: '%s'", server);
-
- if (gdm_wait_for_go) {
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 1 No more flexi servers\n");
- return;
- }
-
- if (type == TYPE_FLEXI_XNEST) {
- gboolean authorized = TRUE;
- struct passwd *pw;
- gid_t oldgid = getegid ();
-
- pw = getpwuid (xnest_uid);
- if (pw == NULL) {
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- /* paranoia */
- NEVER_FAILS_seteuid (0);
-
- if (setegid (pw->pw_gid) < 0)
- NEVER_FAILS_setegid (gdm_daemon_config_get_gdmgid ());
-
- if (seteuid (xnest_uid) < 0) {
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- gdm_assert (xnest_auth_file != NULL);
- gdm_assert (xnest_disp != NULL);
- gdm_assert (xnest_cookie != NULL);
-
- if (authorized &&
- ! gdm_auth_file_check ("handle_flexi_server", xnest_uid, xnest_auth_file, FALSE /* absentok */, NULL))
- authorized = FALSE;
-
- if (authorized &&
- ! check_cookie (xnest_auth_file,
- xnest_disp,
- xnest_cookie)) {
- authorized = FALSE;
- }
-
- /* this must always work, thus the asserts */
- NEVER_FAILS_root_set_euid_egid (0, oldgid);
-
- if (! authorized) {
- /* Sorry dude, you're not doing something
- * right */
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- server_uid = xnest_uid;
- }
-
- if (flexi_servers >= gdm_daemon_config_get_value_int (GDM_KEY_FLEXIBLE_XSERVERS)) {
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 1 No more flexi servers\n");
- return;
- }
-
- bin = ve_first_word (server);
- if (ve_string_empty (server) ||
- g_access (bin, X_OK) != 0) {
- g_free (bin);
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 6 No server binary\n");
- return;
- }
- g_free (bin);
-
- display = gdm_display_alloc (-1, server);
- if G_UNLIKELY (display == NULL) {
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 2 Startup errors\n");
- return;
- }
-
- /* It is kind of ugly that we don't use
- the standard resolution for this, but
- oh well, this makes other things simpler */
- display->handled = handled;
- display->use_chooser = chooser;
-
- if (type == TYPE_FLEXI_XNEST) {
- GdmDisplay *parent;
- gchar *disp, *p;
- gdm_assert (xnest_disp != NULL);
-
- disp = g_strdup (xnest_disp);
- /* whack the screen info */
- p = strchr (disp, ':');
- if (p != NULL)
- p = strchr (p+1, '.');
- if (p != NULL)
- *p = '\0';
- /* if it's on one of the attached displays we started,
- * it's on the console, else it's not (it could be but
- * we aren't sure and we don't want to be fooled) */
- parent = find_display (disp);
- if (/* paranoia */xnest_disp[0] == ':' &&
- parent != NULL &&
- parent->attached)
- display->attached = TRUE;
- else
- display->attached = FALSE;
- g_free (disp);
-
- display->server_uid = server_uid;
- }
-
- flexi_servers++;
-
- display->preset_user = g_strdup (username);
- display->type = type;
- display->socket_conn = conn;
- display->parent_disp = g_strdup (xnest_disp);
- display->parent_auth_file = g_strdup (xnest_auth_file);
- if (conn != NULL)
- gdm_connection_set_close_notify (conn, display, close_conn);
- gdm_daemon_config_display_list_append (display);
-
- if ( ! gdm_display_manage (display)) {
- gdm_display_unmanage (display);
- if (conn != NULL)
- gdm_connection_write (conn,
- "ERROR 2 Startup errors\n");
- return;
- }
- /* Now we wait for the server to start up (or not) */
-}
-
-static void
-handle_dynamic_server (GdmConnection *conn, int type, gchar *key)
-{
- GdmDisplay *disp;
- int disp_num;
- gchar *msg;
- gchar *full;
- gchar *val;
-
- if (!(gdm_daemon_config_get_value_bool (GDM_KEY_DYNAMIC_XSERVERS))) {
- gdm_connection_write (conn, "ERROR 200 Dynamic Displays not allowed\n");
- return;
- }
-
- if ( ! GDM_CONN_AUTH_GLOBAL(conn)) {
- gdm_info (_("DYNAMIC request denied: " "Not authenticated"));
- gdm_connection_write (conn, "ERROR 100 Not authenticated\n");
- return;
- }
-
- if (key == NULL) {
- gdm_connection_write (conn, "ERROR 1 Bad display number <NULL>\n");
- return;
- } else if ( !(isdigit (*key))) {
- msg = g_strdup_printf ("ERROR 1 Bad display number <%s>\n", key);
- gdm_connection_write (conn, msg);
- g_free (msg);
- return;
- }
- disp_num = atoi (key);
-
- if (type == DYNAMIC_ADD) {
- /* prime an X server for launching */
-
- if (mark_display_exists (disp_num)) {
- /* need to skip starting this one again */
- gdm_connection_write (conn, "ERROR 2 Existing display\n");
- return;
- }
-
- full = strchr (key, '=');
- if (full == NULL || *(full + 1) == 0) {
- gdm_connection_write (conn, "ERROR 3 No server string\n");
- return;
- }
-
- val = full + 1;
- disp = gdm_display_alloc (disp_num, val);
-
- if (disp == NULL) {
- gdm_connection_write (conn, "ERROR 4 Display startup failure\n");
- return;
- }
-
- gdm_daemon_config_display_list_insert (disp);
-
- disp->dispstat = DISPLAY_CONFIG;
- disp->removeconf = FALSE;
-
- if (disp_num > gdm_daemon_config_get_high_display_num ())
- gdm_daemon_config_set_high_display_num (disp_num);
-
- gdm_connection_write (conn, "OK\n");
- return;
- }
-
- if (type == DYNAMIC_REMOVE) {
- GSList *li;
- GSList *nli;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- /* shutdown a dynamic X server */
-
- for (li = displays; li != NULL; li = nli) {
- disp = li->data;
- nli = li->next;
- if (disp->dispnum == disp_num) {
- disp->removeconf = TRUE;
- gdm_display_unmanage (disp);
- gdm_connection_write (conn, "OK\n");
- return;
- }
- }
-
- msg = g_strdup_printf ("ERROR 1 Bad display number <%d>\n", disp_num);
- gdm_connection_write (conn, msg);
- return;
- }
-
- if (type == DYNAMIC_RELEASE) {
- /* cause the newly configured X servers to actually run */
- GSList *li;
- GSList *nli;
- gboolean found = FALSE;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- for (li = displays; li != NULL; li = nli) {
- GdmDisplay *disp = li->data;
- nli = li->next;
- if ((disp->dispnum == disp_num) &&
- (disp->dispstat == DISPLAY_CONFIG)) {
- disp->dispstat = DISPLAY_UNBORN;
-
- if ( ! gdm_display_manage (disp)) {
- gdm_display_unmanage (disp);
- }
- found = TRUE;
- }
- }
-
- if (found)
- gdm_connection_write (conn, "OK\n");
- else {
- msg = g_strdup_printf ("ERROR 1 Bad display number <%d>\n", disp_num);
- gdm_connection_write (conn, msg);
- }
-
- /* Now we wait for the server to start up (or not) */
- return;
- }
-}
-
-static void
-sup_handle_auth_local (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- GSList *li;
- char *cookie;
- GSList *displays;
-
- cookie = g_strdup (&msg[strlen (GDM_SUP_AUTH_LOCAL " ")]);
-
- displays = gdm_daemon_config_get_display_list ();
-
- g_strstrip (cookie);
- if (strlen (cookie) != 16*2) /* 16 bytes in hex form */ {
- /* evil, just whack the connection in this case */
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- gdm_connection_close (conn);
- g_free (cookie);
- return;
- }
- /* check if cookie matches one of the attached displays */
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (disp->attached &&
- disp->cookie != NULL &&
- g_ascii_strcasecmp (disp->cookie, cookie) == 0) {
- g_free (cookie);
- GDM_CONNECTION_SET_USER_FLAG
- (conn, GDM_SUP_FLAG_AUTHENTICATED);
- gdm_connection_set_display (conn, disp);
- gdm_connection_write (conn, "OK\n");
- return;
- }
- }
-
- if (gdm_global_cookie != NULL &&
- g_ascii_strcasecmp ((gchar *) gdm_global_cookie, cookie) == 0) {
- g_free (cookie);
- GDM_CONNECTION_SET_USER_FLAG
- (conn, GDM_SUP_FLAG_AUTH_GLOBAL);
- gdm_connection_write (conn, "OK\n");
- return;
- }
-
- /* Hmmm, perhaps this is better defined behaviour */
- GDM_CONNECTION_UNSET_USER_FLAG
- (conn, GDM_SUP_FLAG_AUTHENTICATED);
- GDM_CONNECTION_UNSET_USER_FLAG
- (conn, GDM_SUP_FLAG_AUTH_GLOBAL);
- gdm_connection_set_display (conn, NULL);
- gdm_connection_write (conn, "ERROR 100 Not authenticated\n");
- g_free (cookie);
-}
-
-static void
-sup_handle_attached_servers (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- GString *retMsg;
- GSList *li;
- const gchar *sep = " ";
- char *key;
- int msgLen=0;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- if (strncmp (msg, GDM_SUP_ATTACHED_SERVERS,
- strlen (GDM_SUP_ATTACHED_SERVERS)) == 0)
- msgLen = strlen (GDM_SUP_ATTACHED_SERVERS);
- else if (strncmp (msg, GDM_SUP_CONSOLE_SERVERS,
- strlen (GDM_SUP_CONSOLE_SERVERS)) == 0)
- msgLen = strlen (GDM_SUP_CONSOLE_SERVERS);
-
- key = g_strdup (&msg[msgLen]);
- g_strstrip (key);
-
- retMsg = g_string_new ("OK");
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
-
- if ( ! disp->attached)
- continue;
- if (!(strlen (key)) || (g_pattern_match_simple (key, disp->command))) {
- g_string_append_printf (retMsg, "%s%s,%s,", sep,
- ve_sure_string (disp->name),
- ve_sure_string (disp->login));
- sep = ";";
- if (disp->type == TYPE_FLEXI_XNEST) {
- g_string_append (retMsg, ve_sure_string (disp->parent_disp));
- } else {
- g_string_append_printf (retMsg, "%d", disp->vt);
- }
- }
- }
-
- g_string_append (retMsg, "\n");
- gdm_connection_write (conn, retMsg->str);
- g_free (key);
- g_string_free (retMsg, TRUE);
-}
-
-static void
-sup_handle_get_server_details (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
-
- const gchar *server = &msg[strlen (GDM_SUP_GET_SERVER_DETAILS " ")];
- gchar **splitstr = g_strsplit (server, " ", 2);
- GdmXserver *svr = gdm_daemon_config_find_xserver ((gchar *)splitstr[0]);
-
- if (svr != NULL) {
- if (g_strcasecmp (splitstr[1], "ID") == 0)
- gdm_connection_printf (conn, "OK %s\n", svr->id);
- else if (g_strcasecmp (splitstr[1], "NAME") == 0)
- gdm_connection_printf (conn, "OK %s\n", svr->name);
- else if (g_strcasecmp (splitstr[1], "COMMAND") == 0)
- gdm_connection_printf (conn, "OK %s\n", svr->command);
- else if (g_strcasecmp (splitstr[1], "PRIORITY") == 0)
- gdm_connection_printf (conn, "OK %d\n", svr->priority);
- else if (g_strcasecmp (splitstr[1], "FLEXIBLE") == 0 &&
- svr->flexible)
- gdm_connection_printf (conn, "OK true\n");
- else if (g_strcasecmp (splitstr[1], "FLEXIBLE") == 0 &&
- !svr->flexible)
- gdm_connection_printf (conn, "OK false\n");
- else if (g_strcasecmp (splitstr[1], "CHOOSABLE") == 0 &&
- svr->choosable)
- gdm_connection_printf (conn, "OK true\n");
- else if (g_strcasecmp (splitstr[1], "CHOOSABLE") == 0 &&
- !svr->choosable)
- gdm_connection_printf (conn, "OK false\n");
- else if (g_strcasecmp (splitstr[1], "HANDLED") == 0 &&
- svr->handled)
- gdm_connection_printf (conn, "OK true\n");
- else if (g_strcasecmp (splitstr[1], "HANDLED") == 0 &&
- !svr->handled)
- gdm_connection_printf (conn, "OK false\n");
- else if (g_strcasecmp (splitstr[1], "CHOOSER") == 0 &&
- svr->chooser)
- gdm_connection_printf (conn, "OK true\n");
- else if (g_strcasecmp (splitstr[1], "CHOOSER") == 0 &&
- !svr->chooser)
- gdm_connection_printf (conn, "OK false\n");
- else
- gdm_connection_printf (conn, "ERROR 2 Key not valid\n");
-
- g_strfreev (splitstr);
- } else {
- gdm_connection_printf (conn, "ERROR 1 Server not found\n");
- }
-}
-
-static void
-sup_handle_flexi_xserver (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- char *name;
- const char *command = NULL;
- GdmXserver *svr;
- const char *rest;
- char *username;
- char *end;
- gboolean has_user;
-
- has_user = strncmp (msg, GDM_SUP_FLEXI_XSERVER_USER " ", strlen (GDM_SUP_FLEXI_XSERVER_USER " ")) == 0;
-
- g_debug ("Handling flexi request has-user:%d", has_user);
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn)) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "FLEXI_XSERVER");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- if (has_user) {
- rest = msg + strlen (GDM_SUP_FLEXI_XSERVER_USER " ");
- end = strchr (rest, ' ');
- if (end) {
- username = g_strndup (rest, end - rest);
- rest = end + 1;
- } else {
- username = g_strdup (rest);
- rest = rest + strlen (rest);
- }
- } else {
- rest = msg + strlen (GDM_SUP_FLEXI_XSERVER " ");
- username = NULL;
- }
-
- name = g_strdup (rest);
- g_strstrip (name);
- if (ve_string_empty (name)) {
- g_free (name);
- name = g_strdup (GDM_STANDARD);
- }
-
- svr = gdm_daemon_config_find_xserver (name);
-
- if G_UNLIKELY (svr == NULL) {
- /* Don't print the name to syslog as it might be
- * long and dangerous */
- gdm_error (_("Unknown server type requested; using "
- "standard server."));
- command = gdm_daemon_config_get_value_string (GDM_KEY_STANDARD_XSERVER);
- } else if G_UNLIKELY ( ! svr->flexible) {
- gdm_error (_("Requested server %s not allowed to be "
- "used for flexible servers; using "
- "standard server."), name);
- command = gdm_daemon_config_get_value_string (GDM_KEY_STANDARD_XSERVER);
- } else {
- command = svr->command;
- }
- g_free (name);
-
- handle_flexi_server (conn,
- TYPE_FLEXI,
- command,
- /* It is kind of ugly that we don't use
- the standard resolution for this, but
- oh well, this makes other things simpler */
- svr->handled,
- svr->chooser,
- NULL,
- 0,
- NULL,
- NULL,
- username);
- g_free (username);
-}
-
-static void
-sup_handle_flexi_xnest (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- char *dispname = NULL;
- char *xauthfile = NULL;
- char *cookie = NULL;
- uid_t uid;
- const char *rest;
- char *username;
- char *end;
- gboolean has_user;
-
- has_user = strncmp (msg, GDM_SUP_FLEXI_XNEST_USER " ", strlen (GDM_SUP_FLEXI_XNEST_USER " ")) == 0;
-
- g_debug ("Handling flexi xnest request has-user:%d", has_user);
-
- if (has_user) {
- rest = msg + strlen (GDM_SUP_FLEXI_XNEST_USER " ");
- end = strchr (rest, ' ');
- username = g_strndup (rest, end - rest);
- } else {
- rest = msg;
- username = NULL;
- }
-
- extract_dispname_uid_xauthfile_cookie (rest,
- &dispname,
- &uid,
- &xauthfile,
- &cookie);
-
- if (dispname == NULL) {
- /* Something bogus is going on, so just whack the
- * connection */
- g_free (xauthfile);
- gdm_connection_close (conn);
- g_warning ("Unable to get display name from request");
- return;
- }
-
- /* This is probably a pre-2.2.4.2 client */
- if (xauthfile == NULL || cookie == NULL) {
- /* evil, just whack the connection in this case */
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- gdm_connection_close (conn);
- g_free (cookie);
- return;
- }
-
- handle_flexi_server (conn,
- TYPE_FLEXI_XNEST,
- gdm_daemon_config_get_value_string (GDM_KEY_XNEST),
- TRUE /* handled */,
- FALSE /* chooser */,
- dispname,
- uid,
- xauthfile,
- cookie,
- username);
-
- g_free (dispname);
- g_free (xauthfile);
- g_free (username);
-}
-
-static void
-sup_handle_get_config (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- const char *parms;
- char **splitstr;
- char *retval;
- static gboolean done_prefetch = FALSE;
-
- retval = NULL;
- parms = &msg[strlen (GDM_SUP_GET_CONFIG " ")];
-
- splitstr = g_strsplit (parms, " ", 2);
-
- if (splitstr == NULL || splitstr[0] == NULL) {
- goto out;
- }
-
- /*
- * It is not meaningful to manage this in a per-display
- * fashion since the prefetch program is only run once the
- * for the first display that requests the key. So process
- * this first and return "Unsupported key" for requests
- * after the first request.
- */
- if (strcmp (splitstr[0], GDM_KEY_PRE_FETCH_PROGRAM) == 0) {
- if (done_prefetch) {
- gdm_connection_printf (conn, "OK \n");
- } else {
- gdm_connection_printf (conn, "ERROR 50 Unsupported key <%s>\n", splitstr[0]);
- done_prefetch = TRUE;
- }
- goto out;
- }
-
- if (splitstr[0] != NULL) {
- gboolean res;
-
- /*
- * Note passing in the display is backwards compatible
- * since if it is NULL, it won't try to load the display
- * value at all.
- */
-
- g_debug ("Handling GET_CONFIG: %s for display %s", splitstr[0], splitstr[1]);
-
- res = gdm_daemon_config_to_string (splitstr[0], splitstr[1], &retval);
-
- if (res) {
- gdm_connection_printf (conn, "OK %s\n", retval);
- g_free (retval);
- } else {
- if (gdm_daemon_config_is_valid_key ((gchar *)splitstr[0]))
- gdm_connection_printf (conn, "OK \n");
- else
- gdm_connection_printf (conn,
- "ERROR 50 Unsupported key <%s>\n",
- splitstr[0]);
- }
- }
- out:
- g_strfreev (splitstr);
-}
-
-static gboolean
-is_action_available (GdmDisplay *disp, gchar *action)
-{
- const gchar **allowsyscmd;
- const gchar **rbackeys;
- gboolean sysmenu;
- gboolean ret = FALSE;
- int i;
-
- allowsyscmd = gdm_daemon_config_get_value_string_array (GDM_KEY_ALLOW_LOGOUT_ACTIONS);
- rbackeys = gdm_daemon_config_get_value_string_array (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS);
- sysmenu = gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, disp->name);
-
- if (!disp->attached || !sysmenu) {
- return FALSE;
- }
-
- for (i = 0; allowsyscmd[i] != NULL; i++) {
- if (strcmp (allowsyscmd[i], action) == 0) {
- ret = TRUE;
- break;
- }
- }
-
-#ifdef HAVE_CHKAUTHATTR
- if (ret == TRUE && rbackeys) {
- for (i = 0; rbackeys[i] != NULL; i++) {
- gchar **rbackey = g_strsplit (rbackeys[i], ":", 2);
-
- if (! ve_string_empty (rbackey[0]) &&
- ! ve_string_empty (rbackey[1]) &&
- strcmp (rbackey[0], action) == 0) {
-
- if (!chkauthattr (rbackey[1], disp->login)) {
- g_strfreev (rbackey);
- ret = FALSE;
- break;
- }
-
- }
- g_strfreev (rbackey);
- }
- }
-#endif
-
- return ret;
-}
-
-static void
-sup_handle_query_logout_action (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- GdmLogoutAction logout_action;
- GdmDisplay *disp;
- GString *reply;
- const gchar *sep = " ";
- int i;
-
- disp = gdm_connection_get_display (conn);
-
- /* Only allow locally authenticated connections */
- if (! GDM_CONN_AUTHENTICATED (conn) || disp == NULL) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "QUERY_LOGOUT_ACTION");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- reply = g_string_new ("OK");
-
- logout_action = disp->logout_action;
- if (logout_action == GDM_LOGOUT_ACTION_NONE)
- logout_action = safe_logout_action;
-
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_HALT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_HALT)) {
- g_string_append_printf (reply, "%s%s", sep,
- GDM_SUP_LOGOUT_ACTION_HALT);
- if (logout_action == GDM_LOGOUT_ACTION_HALT)
- g_string_append (reply, "!");
- sep = ";";
- }
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_REBOOT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_REBOOT)) {
- g_string_append_printf (reply, "%s%s", sep,
- GDM_SUP_LOGOUT_ACTION_REBOOT);
- if (logout_action == GDM_LOGOUT_ACTION_REBOOT)
- g_string_append (reply, "!");
- sep = ";";
- }
- if (gdm_daemon_config_get_value_string_array (GDM_KEY_SUSPEND) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_SUSPEND)) {
- g_string_append_printf (reply, "%s%s", sep,
- GDM_SUP_LOGOUT_ACTION_SUSPEND);
- if (logout_action == GDM_LOGOUT_ACTION_SUSPEND)
- g_string_append (reply, "!");
- sep = ";";
- }
-
- if (is_action_available (disp, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE)) {
- for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
- gchar *key_string = NULL;
- key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
-
- if (! ve_string_empty (gdm_daemon_config_get_value_string (key_string))) {
-
- g_free (key_string);
- key_string = g_strdup_printf("%s%d=",
- GDM_KEY_CUSTOM_CMD_IS_PERSISTENT_TEMPLATE, i);
-
- if (gdm_daemon_config_get_value_bool (key_string)) {
- g_string_append_printf (reply, "%s%s%d", sep,
- GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE, i);
- if (logout_action == (GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST + i))
- g_string_append (reply, "!");
- sep = ";";
- }
- }
- g_free(key_string);
- }
- }
-
- g_string_append (reply, "\n");
- gdm_connection_write (conn, reply->str);
- g_string_free (reply, TRUE);
-}
-
-static void
-sup_handle_query_custom_cmd_labels (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
-
- GdmDisplay *disp;
- GString *reply;
- const gchar *sep = " ";
- gboolean sysmenu;
- int i;
-
- disp = gdm_connection_get_display (conn);
- sysmenu = gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, disp->name);
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn) ||
- disp == NULL) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "QUERY_CUSTOM_CMD_LABELS");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- reply = g_string_new ("OK");
-
- for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
- gchar *key_string = NULL;
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
- if (sysmenu && disp->attached &&
- ! ve_string_empty (gdm_daemon_config_get_value_string (key_string))) {
- g_free (key_string);
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_IS_PERSISTENT_TEMPLATE, i);
- if (gdm_daemon_config_get_value_bool (key_string)) {
- g_free (key_string);
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
- g_string_append_printf (reply, "%s%s", sep, gdm_daemon_config_get_value_string (key_string));
- sep = ";";
- }
- }
- g_free(key_string);
- }
-
- g_string_append (reply, "\n");
- gdm_connection_write (conn, reply->str);
- g_string_free (reply, TRUE);
-}
-
-static void
-sup_handle_all_servers (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- GString *reply;
- GSList *li;
- const gchar *sep = " ";
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- reply = g_string_new ("OK");
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- g_string_append_printf (reply, "%s%s,%s", sep,
- ve_sure_string (disp->name),
- ve_sure_string (disp->login));
- sep = ";";
- }
- g_string_append (reply, "\n");
- gdm_connection_write (conn, reply->str);
- g_string_free (reply, TRUE);
-}
-
-static void
-sup_handle_get_server_list (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- gchar *retval = gdm_daemon_config_get_xservers ();
-
- if (retval != NULL) {
- gdm_connection_printf (conn, "OK %s\n", retval);
- g_free (retval);
- } else {
- gdm_connection_printf (conn, "ERROR 1 No servers found\n");
- }
-}
-
-static void
-sup_handle_get_custom_config_file (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- gchar *ret;
-
- ret = gdm_daemon_config_get_custom_config_file ();
- if (ret)
- gdm_connection_printf (conn, "OK %s\n", ret);
- else
- gdm_connection_write (conn,
- "ERROR 1 File not found\n");
-}
-
-static void
-sup_handle_greeterpids (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- GString *reply;
- GSList *li;
- const gchar *sep = " ";
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- reply = g_string_new ("OK");
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (disp->greetpid > 0) {
- g_string_append_printf (reply, "%s%ld",
- sep, (long)disp->greetpid);
- sep = ";";
- }
- }
- g_string_append (reply, "\n");
- gdm_connection_write (conn, reply->str);
- g_string_free (reply, TRUE);
-}
-
-static void
-sup_handle_query_custom_cmd_no_restart_status (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
-
- GdmDisplay *disp;
- GString *reply;
- gboolean sysmenu;
- unsigned long no_restart_status_flag = 0; /* we can store up-to 32 commands this way */
- int i;
-
- disp = gdm_connection_get_display (conn);
- sysmenu = gdm_daemon_config_get_value_bool_per_display (GDM_KEY_SYSTEM_MENU, disp->name);
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn) ||
- disp == NULL) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "QUERY_CUSTOM_CMD_NO_RESTART_STATUS");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- reply = g_string_new ("OK ");
-
- for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
- gchar *key_string = NULL;
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
- if (sysmenu && disp->attached &&
- ! ve_string_empty (gdm_daemon_config_get_value_string (key_string))) {
- g_free (key_string);
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_IS_PERSISTENT_TEMPLATE, i);
- if (gdm_daemon_config_get_value_bool (key_string)) {
- g_free (key_string);
- key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_NO_RESTART_TEMPLATE, i);
- if(gdm_daemon_config_get_value_bool (key_string))
- no_restart_status_flag |= (1 << i);
- }
- }
- g_free(key_string);
- }
-
- g_string_append_printf (reply, "%ld\n", no_restart_status_flag);
- gdm_connection_write (conn, reply->str);
- g_string_free (reply, TRUE);
-}
-
-static void
-sup_handle_set_logout_action (GdmConnection *conn,
- const char *msg,
- gpointer data)
-
-{
- GdmDisplay *disp;
- const gchar *action;
- gboolean was_ok = FALSE;
-
- action = &msg[strlen (GDM_SUP_SET_LOGOUT_ACTION " ")];
- disp = gdm_connection_get_display (conn);
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn) ||
- disp == NULL ||
- ! disp->logged_in) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "SET_LOGOUT_ACTION");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- if (strcmp (action, GDM_SUP_LOGOUT_ACTION_NONE) == 0) {
- disp->logout_action = GDM_LOGOUT_ACTION_NONE;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_HALT) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_HALT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_HALT)) {
- disp->logout_action = GDM_LOGOUT_ACTION_HALT;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_REBOOT) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_REBOOT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_REBOOT)) {
- disp->logout_action = GDM_LOGOUT_ACTION_REBOOT;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_SUSPEND) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_SUSPEND) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_SUSPEND)) {
- disp->logout_action = GDM_LOGOUT_ACTION_SUSPEND;
- was_ok = TRUE;
- }
- else if (strncmp (action, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE,
- strlen (GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE)) == 0 &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE)) {
-
- int cmd_index;
- if (sscanf (action, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE "%d", &cmd_index) == 1) {
- gchar *key_string = NULL;
- key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_index);
- if (! ve_string_empty (gdm_daemon_config_get_value_string (key_string))) {
- disp->logout_action =
- GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST + cmd_index;
- was_ok = TRUE;
- }
- g_free(key_string);
- }
- }
-
- if (was_ok) {
- gdm_connection_write (conn, "OK\n");
- gdm_try_logout_action (disp);
- } else {
- gdm_connection_write (conn, "ERROR 7 Unknown logout action, or not available\n");
- }
-}
-
-static void
-sup_handle_set_safe_logout_action (GdmConnection *conn,
- const char *msg,
- gpointer data)
-
-{
- GdmDisplay *disp;
- const gchar *action;
- gboolean was_ok = FALSE;
-
- action = &msg[strlen (GDM_SUP_SET_SAFE_LOGOUT_ACTION " ")];
- disp = gdm_connection_get_display (conn);
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn) ||
- disp == NULL ||
- ! disp->logged_in) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "SET_LOGOUT_ACTION");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- if (strcmp (action, GDM_SUP_LOGOUT_ACTION_NONE) == 0) {
- safe_logout_action = GDM_LOGOUT_ACTION_NONE;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_HALT) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_HALT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_HALT)) {
- safe_logout_action = GDM_LOGOUT_ACTION_HALT;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_REBOOT) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_REBOOT) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_REBOOT)) {
- safe_logout_action = GDM_LOGOUT_ACTION_REBOOT;
- was_ok = TRUE;
- } else if (strcmp (action, GDM_SUP_LOGOUT_ACTION_SUSPEND) == 0 &&
- gdm_daemon_config_get_value_string_array (GDM_KEY_SUSPEND) &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_SUSPEND)) {
- safe_logout_action = GDM_LOGOUT_ACTION_SUSPEND;
- was_ok = TRUE;
- }
- else if (strncmp (action, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE,
- strlen (GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE)) == 0 &&
- is_action_available (disp, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE)) {
-
- int cmd_index;
- if (sscanf (action, GDM_SUP_LOGOUT_ACTION_CUSTOM_CMD_TEMPLATE "%d", &cmd_index) == 1) {
-
- gchar *key_string = NULL;
- key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_index);
-
- if (! ve_string_empty (gdm_daemon_config_get_value_string (key_string))) {
- safe_logout_action =
- GDM_LOGOUT_ACTION_CUSTOM_CMD_FIRST + cmd_index;
- was_ok = TRUE;
- }
- g_free(key_string);
- }
- }
-
- if (was_ok) {
- gdm_connection_write (conn, "OK\n");
- gdm_try_logout_action (disp);
- } else {
- gdm_connection_write (conn, "ERROR 7 Unknown logout action, or not available\n");
- }
-}
-
-static void
-sup_handle_query_vt (GdmConnection *conn,
- const char *msg,
- gpointer data)
-
-{
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn)) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "QUERY_VT");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
-#if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
- gdm_connection_printf (conn, "OK %d\n", gdm_get_cur_vt ());
-#else
- gdm_connection_write (conn, "ERROR 8 Virtual terminals not supported\n");
-#endif
-}
-
-static void
-sup_handle_set_vt (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
- int vt;
- GSList *li;
- GSList *displays;
-
- displays = gdm_daemon_config_get_display_list ();
-
- if (sscanf (msg, GDM_SUP_SET_VT " %d", &vt) != 1 ||
- vt < 0) {
- gdm_connection_write (conn,
- "ERROR 9 Invalid virtual terminal number\n");
- return;
- }
-
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn)) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "QUERY_VT");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
-#if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
- gdm_change_vt (vt);
- for (li = displays; li != NULL; li = li->next) {
- GdmDisplay *disp = li->data;
- if (disp->vt == vt) {
- send_slave_command (disp, GDM_NOTIFY_TWIDDLE_POINTER);
- break;
- }
- }
- gdm_connection_write (conn, "OK\n");
-#else
- gdm_connection_write (conn, "ERROR 8 Virtual terminals not supported\n");
-#endif
-}
-
-static void
-gdm_handle_user_message (GdmConnection *conn,
- const char *msg,
- gpointer data)
-{
-
- g_debug ("Handling user message: '%s'", msg);
-
- if (gdm_connection_get_message_count (conn) > GDM_SUP_MAX_MESSAGES) {
- g_debug ("Closing connection, %d messages reached", GDM_SUP_MAX_MESSAGES);
- gdm_connection_write (conn, "ERROR 200 Too many messages\n");
- gdm_connection_close (conn);
- return;
- }
-
- if (strncmp (msg, GDM_SUP_AUTH_LOCAL " ",
- strlen (GDM_SUP_AUTH_LOCAL " ")) == 0) {
-
- sup_handle_auth_local (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_FLEXI_XSERVER) == 0) {
- /* Only allow locally authenticated connections */
- if ( ! GDM_CONN_AUTHENTICATED (conn)) {
- gdm_info (_("%s request denied: "
- "Not authenticated"), "FLEXI_XSERVER");
- gdm_connection_write (conn,
- "ERROR 100 Not authenticated\n");
- return;
- }
-
- handle_flexi_server (conn,
- TYPE_FLEXI,
- gdm_daemon_config_get_value_string (GDM_KEY_STANDARD_XSERVER),
- TRUE /* handled */,
- FALSE /* chooser */,
- NULL,
- 0,
- NULL,
- NULL,
- NULL);
- } else if ((strncmp (msg, GDM_SUP_FLEXI_XSERVER_USER " ",
- strlen (GDM_SUP_FLEXI_XSERVER_USER " ")) == 0) ||
- (strncmp (msg, GDM_SUP_FLEXI_XSERVER " ",
- strlen (GDM_SUP_FLEXI_XSERVER " ")) == 0)) {
-
- sup_handle_flexi_xserver (conn, msg, data);
-
- } else if ((strncmp (msg, GDM_SUP_FLEXI_XNEST_USER " ",
- strlen (GDM_SUP_FLEXI_XNEST_USER " ")) == 0) ||
- (strncmp (msg, GDM_SUP_FLEXI_XNEST " ",
- strlen (GDM_SUP_FLEXI_XNEST " ")) == 0)) {
-
- sup_handle_flexi_xnest (conn, msg, data);
-
- } else if ((strncmp (msg, GDM_SUP_ATTACHED_SERVERS,
- strlen (GDM_SUP_ATTACHED_SERVERS)) == 0) ||
- (strncmp (msg, GDM_SUP_CONSOLE_SERVERS,
- strlen (GDM_SUP_CONSOLE_SERVERS)) == 0)) {
-
- sup_handle_attached_servers (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_ALL_SERVERS) == 0) {
-
- sup_handle_all_servers (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_GET_SERVER_LIST) == 0) {
-
- sup_handle_get_server_list (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_GET_SERVER_DETAILS " ",
- strlen (GDM_SUP_GET_SERVER_DETAILS " ")) == 0) {
-
- sup_handle_get_server_details (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_GREETERPIDS) == 0) {
-
- sup_handle_greeterpids (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_UPDATE_CONFIG " ",
- strlen (GDM_SUP_UPDATE_CONFIG " ")) == 0) {
- const char *key;
-
- key = &msg[strlen (GDM_SUP_UPDATE_CONFIG " ")];
-
- if (! gdm_daemon_config_update_key ((gchar *)key))
- gdm_connection_printf (conn, "ERROR 50 Unsupported key <%s>\n", key);
- else
- gdm_connection_write (conn, "OK\n");
- } else if (strncmp (msg, GDM_SUP_GET_CONFIG " ",
- strlen (GDM_SUP_GET_CONFIG " ")) == 0) {
-
- sup_handle_get_config (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_GET_CONFIG_FILE) == 0) {
- /*
- * Value is only non-null if passed in on command line.
- * Otherwise print compiled-in default file location.
- */
- if (config_file == NULL) {
- gdm_connection_printf (conn, "OK %s\n",
- GDM_DEFAULTS_CONF);
- } else {
- gdm_connection_printf (conn, "OK %s\n", config_file);
- }
- } else if (strcmp (msg, GDM_SUP_GET_CUSTOM_CONFIG_FILE) == 0) {
-
- sup_handle_get_custom_config_file (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_QUERY_LOGOUT_ACTION) == 0) {
-
- sup_handle_query_logout_action (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_QUERY_CUSTOM_CMD_LABELS) == 0) {
-
- sup_handle_query_custom_cmd_labels (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_QUERY_CUSTOM_CMD_NO_RESTART_STATUS) == 0) {
-
- sup_handle_query_custom_cmd_no_restart_status (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_SET_LOGOUT_ACTION " ",
- strlen (GDM_SUP_SET_LOGOUT_ACTION " ")) == 0) {
-
- sup_handle_set_logout_action (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_SET_SAFE_LOGOUT_ACTION " ",
- strlen (GDM_SUP_SET_SAFE_LOGOUT_ACTION " ")) == 0) {
-
- sup_handle_set_safe_logout_action (conn, msg, data);
-
- } else if (strcmp (msg, GDM_SUP_QUERY_VT) == 0) {
-
- sup_handle_query_vt (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_SET_VT " ",
- strlen (GDM_SUP_SET_VT " ")) == 0) {
-
- sup_handle_set_vt (conn, msg, data);
-
- } else if (strncmp (msg, GDM_SUP_ADD_DYNAMIC_DISPLAY " ",
- strlen (GDM_SUP_ADD_DYNAMIC_DISPLAY " ")) == 0) {
- gchar *key;
-
- key = g_strdup (&msg[strlen (GDM_SUP_ADD_DYNAMIC_DISPLAY " ")]);
- g_strstrip (key);
- handle_dynamic_server (conn, DYNAMIC_ADD, key);
- g_free (key);
-
- } else if (strncmp (msg, GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ",
- strlen (GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ")) == 0) {
- gchar *key;
-
- key = g_strdup (&msg[strlen (GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ")]);
- g_strstrip (key);
- handle_dynamic_server (conn, DYNAMIC_REMOVE, key);
- g_free (key);
-
- } else if (strncmp (msg, GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ",
- strlen (GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ")) == 0) {
-
- gchar *key;
-
- key = g_strdup (&msg[strlen (GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ")]);
- g_strstrip (key);
- handle_dynamic_server (conn, DYNAMIC_RELEASE, key);
- g_free (key);
-
- } else if (strcmp (msg, GDM_SUP_VERSION) == 0) {
- gdm_connection_write (conn, "GDM " VERSION "\n");
- } else if (strcmp (msg, GDM_SUP_SERVER_BUSY) == 0) {
- if (gdm_connection_is_server_busy (unixconn))
- gdm_connection_write (conn, "OK true\n");
- else
- gdm_connection_write (conn, "OK false\n");
- } else if (strcmp (msg, GDM_SUP_CLOSE) == 0) {
- gdm_connection_close (conn);
- } else {
- gdm_connection_write (conn, "ERROR 0 Not implemented\n");
- gdm_connection_close (conn);
- }
-}
diff --git a/daemon/gdm.h b/daemon/gdm.h
index e13e4185..67758bf1 100644
--- a/daemon/gdm.h
+++ b/daemon/gdm.h
@@ -24,32 +24,6 @@
#define GDM_MAX_PASS 256 /* Define a value for password length. Glibc
* leaves MAX_PASS undefined. */
-/* DO NOTE USE 1, that's used as error if x connection fails usually */
-/* Note that there is no reason why these were a power of two, and note
- * that they have to fit in 256 */
-/* These are the exit codes */
-#define DISPLAY_REMANAGE 2 /* Restart display */
-#define DISPLAY_ABORT 4 /* Houston, we have a problem */
-#define DISPLAY_REBOOT 8 /* Rebewt */
-#define DISPLAY_HALT 16 /* Halt */
-#define DISPLAY_SUSPEND 17 /* Suspend (don't use, use the interrupt) */
-#define DISPLAY_CHOSEN 20 /* successful chooser session,
- restart display */
-#define DISPLAY_RUN_CHOOSER 30 /* Run chooser */
-#define DISPLAY_XFAILED 64 /* X failed */
-#define DISPLAY_GREETERFAILED 65 /* greeter failed (crashed) */
-#define DISPLAY_RESTARTGREETER 127 /* Restart greeter */
-#define DISPLAY_RESTARTGDM 128 /* Restart GDM */
-
-enum {
- DISPLAY_UNBORN /* Not yet started */,
- DISPLAY_ALIVE /* Yay! we're alive (non-XDMCP) */,
- XDMCP_PENDING /* Pending XDMCP display */,
- XDMCP_MANAGED /* Managed XDMCP display */,
- DISPLAY_DEAD /* Left for dead */,
- DISPLAY_CONFIG /* in process of being configured */
-};
-
/* The dreaded miscellaneous category */
#define PIPE_SIZE 4096
@@ -86,9 +60,4 @@ enum {
#define SDTLOGIN_DIR "/var/dt/sdtlogin"
#endif
-/* If id == NULL, then get the first X server */
-void gdm_final_cleanup (void);
-
#endif /* GDM_H */
-
-/* EOF */
diff --git a/daemon/main.c b/daemon/main.c
new file mode 100644
index 00000000..d47a10f5
--- /dev/null
+++ b/daemon/main.c
@@ -0,0 +1,596 @@
+/* -*- 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 <pwd.h>
+#include <grp.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>
+
+/* Needed for signal handling */
+#include "gdm-common.h"
+
+#include "gdm-manager.h"
+#include "gdm-log.h"
+#include "gdm-master-config.h"
+#include "gdm-daemon-config-entries.h"
+
+#include "misc.h"
+
+#define GDM_DBUS_NAME "org.gnome.DisplayManager"
+
+static void bus_proxy_destroyed_cb (DBusGProxy *bus_proxy,
+ GdmManager *manager);
+
+extern char **environ;
+
+static char **stored_argv = NULL;
+static int stored_argc = 0;
+static GList *stored_env = NULL;
+static GdmManager *manager = NULL;
+static GdmDaemonConfig *daemon_config = NULL;
+static uid_t gdm_uid = -1;
+static gid_t gdm_gid = -1;
+
+static gboolean
+timed_exit_cb (GMainLoop *loop)
+{
+ g_main_loop_quit (loop);
+ return FALSE;
+}
+
+static DBusGProxy *
+get_bus_proxy (DBusGConnection *connection)
+{
+ DBusGProxy *bus_proxy;
+
+ bus_proxy = dbus_g_proxy_new_for_name (connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ return bus_proxy;
+}
+
+static gboolean
+acquire_name_on_proxy (DBusGProxy *bus_proxy)
+{
+ GError *error;
+ guint result;
+ gboolean res;
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (bus_proxy == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call (bus_proxy,
+ "RequestName",
+ &error,
+ G_TYPE_STRING, GDM_DBUS_NAME,
+ G_TYPE_UINT, 0,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("Failed to acquire %s: %s", GDM_DBUS_NAME, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to acquire %s", GDM_DBUS_NAME);
+ }
+ goto out;
+ }
+
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ if (error != NULL) {
+ g_warning ("Failed to acquire %s: %s", GDM_DBUS_NAME, error->message);
+ g_error_free (error);
+ } else {
+ g_warning ("Failed to acquire %s", GDM_DBUS_NAME);
+ }
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+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
+bus_reconnect (GdmManager *manager)
+{
+ DBusGConnection *bus;
+ DBusGProxy *bus_proxy;
+ gboolean ret;
+
+ ret = TRUE;
+
+ bus = get_system_bus ();
+ if (bus == NULL) {
+ goto out;
+ }
+
+ bus_proxy = get_bus_proxy (bus);
+ if (bus_proxy == NULL) {
+ g_warning ("Could not construct bus_proxy object; will retry");
+ goto out;
+ }
+
+ if (! acquire_name_on_proxy (bus_proxy) ) {
+ g_warning ("Could not acquire name; will retry");
+ goto out;
+ }
+
+ manager = gdm_manager_new ();
+ if (manager == NULL) {
+ g_warning ("Could not construct manager object");
+ exit (1);
+ }
+
+ g_signal_connect (bus_proxy,
+ "destroy",
+ G_CALLBACK (bus_proxy_destroyed_cb),
+ manager);
+
+ gdm_debug ("Successfully reconnected to D-Bus");
+
+ ret = FALSE;
+
+ out:
+ return ret;
+}
+
+static void
+bus_proxy_destroyed_cb (DBusGProxy *bus_proxy,
+ GdmManager *manager)
+{
+ gdm_debug ("Disconnected from D-Bus");
+
+ g_object_unref (manager);
+ manager = NULL;
+
+ g_timeout_add (3000, (GSourceFunc)bus_reconnect, manager);
+}
+
+static void
+delete_pid (void)
+{
+ unlink (GDM_PID_FILE);
+}
+
+static void
+write_pid (void)
+{
+ int pf;
+ ssize_t written;
+ char pid[9];
+
+ errno = 0;
+ pf = open (GDM_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if (pf < 0) {
+ g_warning (_("Cannot write PID file %s: possibly out of diskspace: %s"),
+ GDM_PID_FILE,
+ g_strerror (errno));
+
+ return;
+ }
+
+ snprintf (pid, sizeof (pid), "%lu\n", (long unsigned) getpid ());
+ errno = 0;
+ written = write (pf, pid, strlen (pid));
+ close (pf);
+
+ if (written < 0) {
+ g_warning (_("Cannot write PID file %s: possibly out of diskspace: %s"),
+ GDM_PID_FILE,
+ g_strerror (errno));
+ return;
+ }
+
+ g_atexit (delete_pid);
+}
+
+static void
+gdm_final_cleanup (void)
+{
+ g_object_unref (manager);
+}
+
+static void
+main_saveenv (void)
+{
+ int i;
+
+ g_list_foreach (stored_env, (GFunc)g_free, NULL);
+ g_list_free (stored_env);
+ stored_env = NULL;
+
+ for (i = 0; environ[i] != NULL; i++) {
+ char *env = environ[i];
+ stored_env = g_list_prepend (stored_env, g_strdup (env));
+ }
+}
+
+static void
+main_restoreenv (void)
+{
+ GList *li;
+
+ ve_clearenv ();
+
+ /* FIXME: leaks */
+
+ for (li = stored_env; li != NULL; li = li->next) {
+ putenv (g_strdup (li->data));
+ }
+}
+
+static void
+gdm_restart_now (void)
+{
+ gdm_info (_("GDM restarting ..."));
+ gdm_final_cleanup ();
+ main_restoreenv ();
+ VE_IGNORE_EINTR (execvp (stored_argv[0], stored_argv));
+ g_warning (_("Failed to restart self"));
+ _exit (1);
+}
+
+static void
+store_argv (int argc,
+ char *argv[])
+{
+ int i;
+
+ stored_argv = g_new0 (char *, argc + 1);
+ for (i = 0; i < argc; i++) {
+ stored_argv[i] = g_strdup (argv[i]);
+ }
+ stored_argv[i] = NULL;
+ stored_argc = argc;
+}
+
+static void
+check_logdir (void)
+{
+ struct stat statbuf;
+ int r;
+ char *log_path;
+
+ log_path = NULL;
+ gdm_daemon_config_get_string_for_id (daemon_config, GDM_ID_LOG_DIR, &log_path);
+
+ VE_IGNORE_EINTR (r = g_stat (log_path, &statbuf));
+ if (r < 0 || ! S_ISDIR (statbuf.st_mode)) {
+ gdm_fail (_("Logdir %s does not exist or isn't a directory."), log_path);
+ }
+
+ g_free (log_path);
+}
+
+static void
+check_servauthdir (const char *auth_path,
+ struct stat *statbuf)
+{
+ int r;
+
+ /* Enter paranoia mode */
+ VE_IGNORE_EINTR (r = g_stat (auth_path, statbuf));
+ if G_UNLIKELY (r < 0) {
+ gdm_fail (_("Authdir %s does not exist. Aborting."), auth_path);
+ }
+
+ if G_UNLIKELY (! S_ISDIR (statbuf->st_mode)) {
+ gdm_fail (_("Authdir %s is not a directory. Aborting."), auth_path);
+ }
+}
+
+static void
+gdm_daemon_check_permissions (uid_t uid,
+ gid_t gid)
+{
+ struct stat statbuf;
+ char *auth_path;
+
+ auth_path = NULL;
+ gdm_daemon_config_get_string_for_id (daemon_config, GDM_ID_LOG_DIR, &auth_path);
+
+ /* Enter paranoia mode */
+ check_servauthdir (auth_path, &statbuf);
+
+ NEVER_FAILS_root_set_euid_egid (0, 0);
+
+ /* Now set things up for us as */
+ chown (auth_path, 0, gid);
+ g_chmod (auth_path, (S_IRWXU|S_IRWXG|S_ISVTX));
+
+ NEVER_FAILS_root_set_euid_egid (uid, gid);
+
+ /* Again paranoid */
+ check_servauthdir (auth_path, &statbuf);
+
+ if G_UNLIKELY (statbuf.st_uid != 0 || statbuf.st_gid != gid) {
+ gdm_fail (_("Authdir %s is not owned by user %d, group %d. Aborting."),
+ auth_path,
+ (int)uid,
+ (int)gid);
+ }
+
+ if G_UNLIKELY (statbuf.st_mode != (S_IFDIR|S_IRWXU|S_IRWXG|S_ISVTX)) {
+ gdm_fail (_("Authdir %s has wrong permissions %o. Should be %o. Aborting."),
+ auth_path,
+ statbuf.st_mode,
+ (S_IRWXU|S_IRWXG|S_ISVTX));
+ }
+
+ g_free (auth_path);
+}
+
+static void
+gdm_daemon_change_user (uid_t *uidp,
+ gid_t *gidp)
+{
+ char *username;
+ char *groupname;
+ uid_t uid;
+ gid_t gid;
+ struct passwd *pwent;
+ struct group *grent;
+
+ username = NULL;
+ groupname = NULL;
+ uid = 0;
+ gid = 0;
+
+ gdm_daemon_config_get_string_for_id (daemon_config, GDM_ID_USER, &username);
+ gdm_daemon_config_get_string_for_id (daemon_config, GDM_ID_GROUP, &groupname);
+
+ /* Lookup user and groupid for the GDM user */
+ pwent = getpwnam (username);
+
+ /* Set uid and gid */
+ if G_UNLIKELY (pwent == NULL) {
+ gdm_fail (_("Can't find the GDM user '%s'. Aborting!"), username);
+ } else {
+ uid = pwent->pw_uid;
+ }
+
+ if G_UNLIKELY (uid == 0) {
+ gdm_fail (_("The GDM user should not be root. Aborting!"));
+ }
+
+ grent = getgrnam (groupname);
+
+ if G_UNLIKELY (grent == NULL) {
+ gdm_fail (_("Can't find the GDM group '%s'. Aborting!"), groupname);
+ } else {
+ gid = grent->gr_gid;
+ }
+
+ if G_UNLIKELY (gid == 0) {
+ gdm_fail (_("The GDM group should not be root. Aborting!"));
+ }
+
+ /* gid remains `gdm' */
+ NEVER_FAILS_root_set_euid_egid (uid, gid);
+
+ if (uidp != NULL) {
+ *uidp = uid;
+ }
+
+ if (gidp != NULL) {
+ *gidp = gid;
+ }
+
+ g_free (username);
+ g_free (groupname);
+}
+
+static void
+setup_signal_handlers (void)
+{
+ /* FIXME */
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GMainLoop *loop;
+ GOptionContext *context;
+ DBusGProxy *bus_proxy;
+ DBusGConnection *connection;
+ int ret;
+ int i;
+ gboolean debug;
+ static char *config_file = NULL;
+ static gboolean no_daemon = FALSE;
+ static gboolean no_console = FALSE;
+ static gboolean do_timed_exit = FALSE;
+ static gboolean print_version = FALSE;
+ static GOptionEntry entries [] = {
+ { "config", 0, 0, G_OPTION_ARG_STRING, &config_file, N_("Alternative GDM System Defaults configuration file"), N_("CONFIGFILE") },
+
+ { "nodaemon", 0, 0, G_OPTION_ARG_NONE, &no_daemon, N_("Don't become a daemon"), NULL },
+ { "no-console", 0, 0, G_OPTION_ARG_NONE, &no_console, N_("No console (static) servers to be run"), NULL },
+
+ { "timed-exit", 0, 0, G_OPTION_ARG_NONE, &do_timed_exit, N_("Exit after a time - for debugging"), NULL },
+ { "version", 0, 0, G_OPTION_ARG_NONE, &print_version, N_("Print GDM version"), NULL },
+
+ { NULL }
+ };
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain (GETTEXT_PACKAGE);
+ setlocale (LC_ALL, "");
+
+ ret = 1;
+
+ g_type_init ();
+
+ store_argv (argc, argv);
+ main_saveenv ();
+
+ context = g_option_context_new (_("GNOME Display Manager"));
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ /* preprocess the arguments to support the xdm style -nodaemon
+ * option
+ */
+ for (i = 0; i < argc; i++) {
+ if (strcmp (argv[i], "-nodaemon") == 0)
+ argv[i] = (char *) "--nodaemon";
+ }
+
+ g_option_context_parse (context, &argc, &argv, NULL);
+ g_option_context_free (context);
+
+ if (! no_daemon && daemon (0, 0)) {
+ g_error ("Could not daemonize: %s", g_strerror (errno));
+ }
+
+ connection = get_system_bus ();
+ if (connection == NULL) {
+ goto out;
+ }
+
+ bus_proxy = get_bus_proxy (connection);
+ if (bus_proxy == NULL) {
+ g_warning ("Could not construct bus_proxy object; bailing out");
+ goto out;
+ }
+
+ if (! acquire_name_on_proxy (bus_proxy) ) {
+ g_warning ("Could not acquire name; bailing out");
+ goto out;
+ }
+
+ gdm_log_init ();
+
+ daemon_config = gdm_daemon_config_new ();
+ gdm_daemon_config_load (daemon_config);
+
+ debug = FALSE;
+ gdm_daemon_config_get_bool_for_id (daemon_config, GDM_ID_DEBUG, &debug);
+ gdm_log_set_debug (debug);
+
+ gdm_daemon_change_user (&gdm_uid, &gdm_gid);
+ gdm_daemon_check_permissions (gdm_uid, gdm_gid);
+ NEVER_FAILS_root_set_euid_egid (0, 0);
+ check_logdir ();
+
+ /* XDM compliant error message */
+ if (getuid () != 0) {
+ /* make sure the pid file doesn't get wiped */
+ g_warning (_("Only root wants to run GDM"));
+ exit (-1);
+ }
+
+ /* pid file */
+ delete_pid ();
+ write_pid ();
+
+ g_chdir (AUTHDIR);
+
+#ifdef __sun
+ g_unlink (SDTLOGIN_DIR);
+ g_mkdir (SDTLOGIN_DIR, 0700);
+#endif
+
+ setup_signal_handlers ();
+
+ manager = gdm_manager_new ();
+
+ if (manager == NULL) {
+ goto out;
+ }
+
+ g_signal_connect (bus_proxy,
+ "destroy",
+ G_CALLBACK (bus_proxy_destroyed_cb),
+ manager);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ if (do_timed_exit) {
+ g_timeout_add (1000 * 30, (GSourceFunc) timed_exit_cb, loop);
+ }
+
+ gdm_manager_start (manager);
+
+ g_main_loop_run (loop);
+
+ if (manager != NULL) {
+ g_object_unref (manager);
+ }
+ if (daemon_config != NULL) {
+ g_object_unref (daemon_config);
+ }
+
+ g_main_loop_unref (loop);
+
+ ret = 0;
+
+ out:
+
+ return ret;
+}
diff --git a/daemon/misc.c b/daemon/misc.c
index a7ff2337..6d14193d 100644
--- a/daemon/misc.c
+++ b/daemon/misc.c
@@ -172,37 +172,6 @@ have_ipv6 (void)
}
#endif
-void
-gdm_fdprintf (int fd, const gchar *format, ...)
-{
- va_list args;
- gchar *s;
- int written, len;
-
- va_start (args, format);
- s = g_strdup_vprintf (format, args);
- va_end (args);
-
- len = strlen (s);
-
- if (len == 0) {
- g_free (s);
- return;
- }
-
- written = 0;
- while (written < len) {
- int w;
- VE_IGNORE_EINTR (w = write (fd, &s[written], len - written));
- if (w < 0)
- /* evil! */
- break;
- written += w;
- }
-
- g_free (s);
-}
-
/*
* Clear environment, but keep the i18n ones,
* note that this leaks memory so only use before exec
@@ -663,97 +632,6 @@ gdm_exec_wait (char * const *argv,
return -1;
}
-static int sigchld_blocked = 0;
-static sigset_t sigchldblock_mask, sigchldblock_oldmask;
-
-static int sigterm_blocked = 0;
-static sigset_t sigtermblock_mask, sigtermblock_oldmask;
-
-static int sigusr2_blocked = 0;
-static sigset_t sigusr2block_mask, sigusr2block_oldmask;
-
-void
-gdm_sigchld_block_push (void)
-{
- sigchld_blocked++;
-
- if (sigchld_blocked == 1) {
- /* Set signal mask */
- sigemptyset (&sigchldblock_mask);
- sigaddset (&sigchldblock_mask, SIGCHLD);
- sigprocmask (SIG_BLOCK, &sigchldblock_mask, &sigchldblock_oldmask);
- }
-}
-
-void
-gdm_sigchld_block_pop (void)
-{
- sigchld_blocked --;
-
- if (sigchld_blocked == 0) {
- /* Reset signal mask back */
- sigprocmask (SIG_SETMASK, &sigchldblock_oldmask, NULL);
- }
-}
-
-void
-gdm_sigterm_block_push (void)
-{
- sigterm_blocked++;
-
- if (sigterm_blocked == 1) {
- /* Set signal mask */
- sigemptyset (&sigtermblock_mask);
- sigaddset (&sigtermblock_mask, SIGTERM);
- sigaddset (&sigtermblock_mask, SIGINT);
- sigaddset (&sigtermblock_mask, SIGHUP);
- sigprocmask (SIG_BLOCK, &sigtermblock_mask, &sigtermblock_oldmask);
- }
-}
-
-void
-gdm_sigterm_block_pop (void)
-{
- sigterm_blocked --;
-
- if (sigterm_blocked == 0) {
- /* Reset signal mask back */
- sigprocmask (SIG_SETMASK, &sigtermblock_oldmask, NULL);
- }
-}
-
-void
-gdm_sigusr2_block_push (void)
-{
- sigset_t oldmask;
-
- if (sigusr2_blocked == 0) {
- /* Set signal mask */
- sigemptyset (&sigusr2block_mask);
- sigaddset (&sigusr2block_mask, SIGUSR2);
- sigprocmask (SIG_BLOCK, &sigusr2block_mask, &oldmask);
- }
-
- sigusr2_blocked++;
-
- sigusr2block_oldmask = oldmask;
-}
-
-void
-gdm_sigusr2_block_pop (void)
-{
- sigset_t oldmask;
-
- oldmask = sigusr2block_oldmask;
-
- sigusr2_blocked--;
-
- if (sigusr2_blocked == 0) {
- /* Reset signal mask back */
- sigprocmask (SIG_SETMASK, &sigusr2block_oldmask, NULL);
- }
-}
-
pid_t
gdm_fork_extra (void)
{
@@ -879,84 +757,6 @@ gdm_ensure_sanity (void)
NEVER_FAILS_root_set_euid_egid (old_euid, old_egid);
}
-const GList *
-gdm_address_peek_local_list (void)
-{
- static GList *the_list = NULL;
- static time_t last_time = 0;
- char hostbuf[BUFSIZ];
- struct addrinfo hints;
- struct addrinfo *result;
- struct addrinfo *res;
-
- /* Don't check more then every 5 seconds */
- if (last_time + 5 > time (NULL)) {
- return the_list;
- }
-
- g_list_foreach (the_list, (GFunc)g_free, NULL);
- g_list_free (the_list);
- the_list = NULL;
-
- last_time = time (NULL);
-
- hostbuf[BUFSIZ-1] = '\0';
- if (gethostname (hostbuf, BUFSIZ-1) != 0) {
- gdm_debug ("%s: Could not get server hostname, using localhost", "gdm_peek_local_address_list");
- snprintf (hostbuf, BUFSIZ-1, "localhost");
- }
-
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_INET;
-#ifdef ENABLE_IPV6
- hints.ai_family |= AF_INET6;
-#endif
-
- if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
- gdm_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
-
- return NULL;
- }
-
- for (res = result; res != NULL; res = res->ai_next) {
- struct sockaddr_storage *sa;
-
- sa = g_memdup (res->ai_addr, res->ai_addrlen);
- the_list = g_list_append (the_list, sa);
- }
-
- if (result) {
- freeaddrinfo (result);
- result = NULL;
- }
-
- return the_list;
-}
-
-
-gboolean
-gdm_address_is_local (struct sockaddr_storage *sa)
-{
- const GList *list;
-
- if (gdm_address_is_loopback (sa)) {
- return TRUE;
- }
-
- list = gdm_address_peek_local_list ();
-
- while (list != NULL) {
- struct sockaddr_storage *addr = list->data;
-
- if (gdm_address_equal (sa, addr)) {
- return TRUE;
- }
-
- list = list->next;
- }
-
- return FALSE;
-}
gboolean
gdm_setup_gids (const char *login, gid_t gid)
@@ -1070,117 +870,6 @@ gdm_test_opt (const char *cmd, const char *help, const char *option)
return got_it;
}
-int
-gdm_fdgetc (int fd)
-{
- char buf[1];
- int bytes;
-
- VE_IGNORE_EINTR (bytes = read (fd, buf, 1));
- if (bytes != 1)
- return EOF;
- else
- return (int)buf[0];
-}
-
-char *
-gdm_fdgets (int fd)
-{
- int c;
- int bytes = 0;
- GString *gs = g_string_new (NULL);
- for (;;) {
- c = gdm_fdgetc (fd);
- if (c == '\n')
- return g_string_free (gs, FALSE);
- /* on EOF */
- if (c < 0) {
- if (bytes == 0) {
- g_string_free (gs, TRUE);
- return NULL;
- } else {
- return g_string_free (gs, FALSE);
- }
- } else {
- bytes++;
- g_string_append_c (gs, c);
- }
- }
-}
-
-void
-gdm_close_all_descriptors (int from, int except, int except2)
-{
- DIR *dir;
- struct dirent *ent;
- GSList *openfds = NULL;
-
- /*
- * Evil, but less evil then going to _SC_OPEN_MAX
- * which can be very VERY large
- */
- dir = opendir ("/proc/self/fd/"); /* This is the Linux dir */
- if (dir == NULL)
- dir = opendir ("/dev/fd/"); /* This is the FreeBSD dir */
- if G_LIKELY (dir != NULL) {
- GSList *li;
- while ((ent = readdir (dir)) != NULL) {
- int fd;
- if (ent->d_name[0] == '.')
- continue;
- fd = atoi (ent->d_name);
- if (fd >= from && fd != except && fd != except2)
- openfds = g_slist_prepend (openfds, GINT_TO_POINTER (fd));
- }
- closedir (dir);
- for (li = openfds; li != NULL; li = li->next) {
- int fd = GPOINTER_TO_INT (li->data);
- VE_IGNORE_EINTR (close (fd));
- }
- g_slist_free (openfds);
- } else {
- int i;
- int max = sysconf (_SC_OPEN_MAX);
- /*
- * Don't go higher then this. This is
- * a safety measure to not hang on crazy
- * systems
- */
- if G_UNLIKELY (max > 4096) {
- /* FIXME: warn about this perhaps */
- /*
- * Try an open, in case we're really
- * leaking fds somewhere badly, this
- * should be very high
- */
- i = gdm_open_dev_null (O_RDONLY);
- max = MAX (i+1, 4096);
- }
- for (i = from; i < max; i++) {
- if G_LIKELY (i != except && i != except2)
- VE_IGNORE_EINTR (close (i));
- }
- }
-}
-
-int
-gdm_open_dev_null (mode_t mode)
-{
- int ret;
- VE_IGNORE_EINTR (ret = open ("/dev/null", mode));
- if G_UNLIKELY (ret < 0) {
- /*
- * Never output anything, we're likely in some
- * strange state right now
- */
- gdm_signal_ignore (SIGPIPE);
- VE_IGNORE_EINTR (close (2));
- gdm_fail ("Cannot open /dev/null, system on crack!");
- }
-
- return ret;
-}
-
void
gdm_unset_signals (void)
{
@@ -1206,439 +895,6 @@ gdm_unset_signals (void)
#endif
}
-void
-gdm_signal_ignore (int signal)
-{
- struct sigaction ign_signal;
-
- ign_signal.sa_handler = SIG_IGN;
- ign_signal.sa_flags = SA_RESTART;
- sigemptyset (&ign_signal.sa_mask);
-
- if G_UNLIKELY (sigaction (signal, &ign_signal, NULL) < 0)
- gdm_error (_("%s: Error setting signal %d to %s"),
- "gdm_signal_ignore", signal, "SIG_IGN");
-}
-
-void
-gdm_signal_default (int signal)
-{
- struct sigaction def_signal;
-
- def_signal.sa_handler = SIG_DFL;
- def_signal.sa_flags = SA_RESTART;
- sigemptyset (&def_signal.sa_mask);
-
- if G_UNLIKELY (sigaction (signal, &def_signal, NULL) < 0)
- gdm_error (_("%s: Error setting signal %d to %s"),
- "gdm_signal_ignore", signal, "SIG_DFL");
-}
-
-static GdmHostent *
-fillout_addrinfo (struct addrinfo *res,
- struct sockaddr *ia,
- const char *name)
-{
- GdmHostent *he;
- gint i;
- gint addr_count = 0;
- struct addrinfo *tempaddrinfo;
-
- he = g_new0 (GdmHostent, 1);
-
- he->addrs = NULL;
- he->addr_count = 0;
-
- if (res != NULL && res->ai_canonname != NULL) {
- he->hostname = g_strdup (res->ai_canonname);
- he->not_found = FALSE;
- } else {
- he->not_found = TRUE;
- if (name != NULL)
- he->hostname = g_strdup (name);
- else {
- static char buffer6[INET6_ADDRSTRLEN];
- static char buffer[INET_ADDRSTRLEN];
- const char *new = NULL;
-
- if (ia->sa_family == AF_INET6) {
- if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)ia)->sin6_addr)) {
- new = inet_ntop (AF_INET, &(((struct sockaddr_in6 *)ia)->sin6_addr.s6_addr[12]), buffer, sizeof (buffer));
- } else {
- new = inet_ntop (AF_INET6, &((struct sockaddr_in6 *)ia)->sin6_addr, buffer6, sizeof (buffer6));
- }
- } else if (ia->sa_family == AF_INET) {
- new = inet_ntop (AF_INET, &((struct sockaddr_in *)ia)->sin_addr, buffer, sizeof (buffer));
- }
-
- if (new != NULL) {
- he->hostname = g_strdup (new);
- } else {
- he->hostname = NULL;
- }
- }
- }
-
- tempaddrinfo = res;
-
- while (res != NULL) {
- addr_count++;
- res = res->ai_next;
- }
-
- he->addrs = g_new0 (struct sockaddr_storage, addr_count);
- he->addr_count = addr_count;
- res = tempaddrinfo;
- for (i = 0; ; i++) {
- if (res == NULL)
- break;
-
- if ((res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) {
- (he->addrs)[i] = *(struct sockaddr_storage *)(res->ai_addr);
- }
-
- res = res->ai_next;
- }
-
- /* We don't want the ::ffff: that could arise here */
- if (he->hostname != NULL &&
- strncmp (he->hostname, "::ffff:", 7) == 0) {
- strcpy (he->hostname, he->hostname + 7);
- }
-
- return he;
-}
-
-static gboolean do_jumpback = FALSE;
-static Jmp_buf signal_jumpback;
-static struct sigaction oldterm, oldint, oldhup;
-
-static void
-jumpback_sighandler (int signal)
-{
- /*
- * This avoids a race see Note below.
- * We want to jump back only on the first
- * signal invocation, even if the signal
- * handler didn't return.
- */
- gboolean old_do_jumpback = do_jumpback;
- do_jumpback = FALSE;
-
- if (signal == SIGINT)
- oldint.sa_handler (signal);
- else if (signal == SIGTERM)
- oldint.sa_handler (signal);
- else if (signal == SIGHUP)
- oldint.sa_handler (signal);
- /* No others should be set up */
-
- /* Note that we may not get here since
- the SIGTERM handler in slave.c
- might have in fact done the big Longjmp
- to the slave's death */
-
- if (old_do_jumpback) {
- Longjmp (signal_jumpback, 1);
- }
-}
-
-/*
- * This sets up interruptes to be proxied and the
- * gethostbyname/addr to be whacked using longjmp,
- * in case INT/TERM/HUP was gotten in which case
- * we no longer care for the result of the
- * resolution.
- */
-#define SETUP_INTERRUPTS_FOR_TERM_DECLS \
- struct sigaction term;
-
-#define SETUP_INTERRUPTS_FOR_TERM_SETUP \
- do_jumpback = FALSE; \
- \
- term.sa_handler = jumpback_sighandler; \
- term.sa_flags = SA_RESTART; \
- sigemptyset (&term.sa_mask); \
- \
- if G_UNLIKELY (sigaction (SIGTERM, &term, &oldterm) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "TERM", strerror (errno)); \
- \
- if G_UNLIKELY (sigaction (SIGINT, &term, &oldint) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "INT", strerror (errno)); \
- \
- if G_UNLIKELY (sigaction (SIGHUP, &term, &oldhup) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "HUP", strerror (errno)); \
-
-#define SETUP_INTERRUPTS_FOR_TERM_TEARDOWN \
- do_jumpback = FALSE; \
- \
- if G_UNLIKELY (sigaction (SIGTERM, &oldterm, NULL) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "TERM", strerror (errno)); \
- \
- if G_UNLIKELY (sigaction (SIGINT, &oldint, NULL) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "INT", strerror (errno)); \
- \
- if G_UNLIKELY (sigaction (SIGHUP, &oldhup, NULL) < 0) \
- gdm_fail (_("%s: Error setting up %s signal handler: %s"), \
- "SETUP_INTERRUPTS_FOR_TERM", "HUP", strerror (errno));
-
-GdmHostent *
-gdm_gethostbyname (const char *name)
-{
- struct addrinfo hints;
- /* static because of Setjmp */
- static struct addrinfo *result;
-
- SETUP_INTERRUPTS_FOR_TERM_DECLS
-
- /* The cached address */
- static GdmHostent *he = NULL;
- static time_t last_time = 0;
- static char *cached_hostname = NULL;
-
- if (cached_hostname != NULL &&
- strcmp (cached_hostname, name) == 0) {
- /* Don't check more then every 60 seconds */
- if (last_time + 60 > time (NULL))
- return gdm_hostent_copy (he);
- }
-
- SETUP_INTERRUPTS_FOR_TERM_SETUP
-
- if (Setjmp (signal_jumpback) == 0) {
- do_jumpback = TRUE;
-
- /* Find client hostname */
- memset (&hints, 0, sizeof (hints));
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_CANONNAME;
-
- if (result) {
- freeaddrinfo (result);
- result = NULL;
- }
-
- getaddrinfo (name, NULL, &hints, &result);
- do_jumpback = FALSE;
- } else {
- /* Here we got interrupted */
- result = NULL;
- }
-
- SETUP_INTERRUPTS_FOR_TERM_TEARDOWN
-
- g_free (cached_hostname);
- cached_hostname = g_strdup (name);
-
- gdm_hostent_free (he);
-
- he = fillout_addrinfo (result, NULL, name);
-
- last_time = time (NULL);
- return gdm_hostent_copy (he);
-}
-
-GdmHostent *
-gdm_gethostbyaddr (struct sockaddr_storage *ia)
-{
- struct addrinfo hints;
- /* static because of Setjmp */
- static struct addrinfo *result = NULL;
- struct sockaddr_in6 sin6;
- struct sockaddr_in sin;
- static struct in6_addr cached_addr6;
-
- SETUP_INTERRUPTS_FOR_TERM_DECLS
-
- /* The cached address */
- static GdmHostent *he = NULL;
- static time_t last_time = 0;
- static struct in_addr cached_addr;
-
- if (last_time != 0) {
- if ((ia->ss_family == AF_INET6) && (memcmp (cached_addr6.s6_addr, ((struct sockaddr_in6 *) ia)->sin6_addr.s6_addr, sizeof (struct in6_addr)) == 0)) {
- /* Don't check more then every 60 seconds */
- if (last_time + 60 > time (NULL))
- return gdm_hostent_copy (he);
- } else if (ia->ss_family == AF_INET) {
- if (memcmp (&cached_addr, &(((struct sockaddr_in *)ia)->sin_addr), sizeof (struct in_addr)) == 0) {
- /* Don't check more then every 60 seconds */
- if (last_time + 60 > time (NULL))
- return gdm_hostent_copy (he);
- }
- }
- }
-
- SETUP_INTERRUPTS_FOR_TERM_SETUP
-
- if (Setjmp (signal_jumpback) == 0) {
- do_jumpback = TRUE;
-
- /* Find client hostname */
- memset (&hints, 0, sizeof (hints));
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_CANONNAME;
-
- if (result) {
- freeaddrinfo (result);
- result = NULL;
- }
-
- if (ia->ss_family == AF_INET6) {
- char buffer6[INET6_ADDRSTRLEN];
-
- inet_ntop (AF_INET6, &((struct sockaddr_in6 *)ia)->sin6_addr, buffer6, sizeof (buffer6));
-
- /*
- * In the case of IPv6 mapped address strip the
- * ::ffff: and lookup as an IPv4 address
- */
- if (strncmp (buffer6, "::ffff:", 7) == 0) {
- char *temp= (buffer6 + 7);
- strcpy (buffer6, temp);
- }
- getaddrinfo (buffer6, NULL, &hints, &result);
-
- } else if (ia->ss_family == AF_INET) {
- char buffer[INET_ADDRSTRLEN];
-
- inet_ntop (AF_INET, &((struct sockaddr_in *)ia)->sin_addr, buffer, sizeof (buffer));
-
- getaddrinfo (buffer, NULL, &hints, &result);
- }
-
- do_jumpback = FALSE;
- } else {
- /* Here we got interrupted */
- result = NULL;
- }
-
- SETUP_INTERRUPTS_FOR_TERM_TEARDOWN
-
- if (ia->ss_family == AF_INET6) {
- memcpy (cached_addr6.s6_addr, ((struct sockaddr_in6 *)ia)->sin6_addr.s6_addr, sizeof (struct in6_addr));
- memset (&sin6, 0, sizeof (sin6));
- memcpy (sin6.sin6_addr.s6_addr, cached_addr6.s6_addr, sizeof (struct in6_addr));
- sin6.sin6_family = AF_INET6;
- he = fillout_addrinfo (result, (struct sockaddr *)&sin6, NULL);
- }
- else if (ia->ss_family == AF_INET) {
- memcpy (&(cached_addr.s_addr), &(((struct sockaddr_in *)ia)->sin_addr.s_addr), sizeof (struct in_addr));
- memset (&sin, 0, sizeof (sin));
- memcpy (&sin.sin_addr, &cached_addr, sizeof (struct in_addr));
- sin.sin_family = AF_INET;
- he = fillout_addrinfo (result, (struct sockaddr *)&sin, NULL);
- }
-
- last_time = time (NULL);
- return gdm_hostent_copy (he);
-}
-
-GdmHostent *
-gdm_hostent_copy (GdmHostent *he)
-{
- GdmHostent *cpy;
-
- if (he == NULL)
- return NULL;
-
- cpy = g_new0 (GdmHostent, 1);
- cpy->not_found = he->not_found;
- cpy->hostname = g_strdup (he->hostname);
- if (he->addr_count == 0) {
- cpy->addr_count = 0;
- cpy->addrs = NULL;
- } else {
- cpy->addr_count = he->addr_count;
- cpy->addrs = g_new0 (struct sockaddr_storage, he->addr_count);
- memcpy (cpy->addrs, he->addrs, sizeof (struct sockaddr_storage) * he->addr_count);
- }
- return cpy;
-}
-
-void
-gdm_hostent_free (GdmHostent *he)
-{
- if (he == NULL)
- return;
- g_free (he->hostname);
- he->hostname = NULL;
-
- g_free (he->addrs);
- he->addrs = NULL;
- he->addr_count = 0;
-
- g_free (he);
-}
-
-/* Like fopen with "w" */
-FILE *
-gdm_safe_fopen_w (const char *file, mode_t perm)
-{
- int fd;
- FILE *ret;
- VE_IGNORE_EINTR (g_unlink (file));
- do {
- errno = 0;
- fd = open (file, O_EXCL|O_CREAT|O_TRUNC|O_WRONLY
-#ifdef O_NOCTTY
- |O_NOCTTY
-#endif
-#ifdef O_NOFOLLOW
- |O_NOFOLLOW
-#endif
- , perm);
- } while G_UNLIKELY (errno == EINTR);
- if (fd < 0)
- return NULL;
- VE_IGNORE_EINTR (ret = fdopen (fd, "w"));
- return ret;
-}
-
-/* Like fopen with "a+" */
-FILE *
-gdm_safe_fopen_ap (const char *file, mode_t perm)
-{
- int fd;
- FILE *ret;
-
- if (g_access (file, F_OK) == 0) {
- do {
- errno = 0;
- fd = open (file, O_APPEND|O_RDWR
-#ifdef O_NOCTTY
- |O_NOCTTY
-#endif
-#ifdef O_NOFOLLOW
- |O_NOFOLLOW
-#endif
- );
- } while G_UNLIKELY (errno == EINTR);
- } else {
- /* Doesn't exist, open with O_EXCL */
- do {
- errno = 0;
- fd = open (file, O_EXCL|O_CREAT|O_RDWR
-#ifdef O_NOCTTY
- |O_NOCTTY
-#endif
-#ifdef O_NOFOLLOW
- |O_NOFOLLOW
-#endif
- , perm);
- } while G_UNLIKELY (errno == EINTR);
- }
- if (fd < 0)
- return NULL;
- VE_IGNORE_EINTR (ret = fdopen (fd, "a+"));
- return ret;
-}
-
#ifdef RLIM_NLIMITS
#define NUM_OF_LIMITS RLIM_NLIMITS
#else /* ! RLIM_NLIMITS */
@@ -1954,15 +1210,6 @@ gdm_sleep_no_signal (int secs)
}
char *
-gdm_make_filename (const char *dir, const char *name, const char *extension)
-{
- char *base = g_strconcat (name, extension, NULL);
- char *full = g_build_filename (dir, base, NULL);
- g_free (base);
- return full;
-}
-
-char *
gdm_ensure_extension (const char *name, const char *extension)
{
const char *p;
@@ -2162,4 +1409,3 @@ gdm_read_default (gchar *key)
#endif
}
-/* EOF */
diff --git a/daemon/misc.h b/daemon/misc.h
index 56a83217..2a7500a3 100644
--- a/daemon/misc.h
+++ b/daemon/misc.h
@@ -25,10 +25,6 @@
#include "gdm.h"
#include "display.h"
-void gdm_fdprintf (int fd, const gchar *format, ...) G_GNUC_PRINTF (2, 3);
-int gdm_fdgetc (int fd);
-char *gdm_fdgets (int fd);
-
/* clear environment, but keep the i18n ones (LANG, LC_ALL, etc...),
* note that this leak memory so only use before exec */
void gdm_clearenv_no_lang (void);
@@ -45,47 +41,15 @@ int gdm_exec_wait (char * const *argv, gboolean no_display,
* exists and has the correct permissions */
void gdm_ensure_sanity (void);
-/* This is for race free forks */
-void gdm_sigchld_block_push (void);
-void gdm_sigchld_block_pop (void);
-void gdm_sigterm_block_push (void);
-void gdm_sigterm_block_pop (void);
-void gdm_sigusr2_block_push (void);
-void gdm_sigusr2_block_pop (void);
-
pid_t gdm_fork_extra (void);
void gdm_wait_for_extra (pid_t pid, int *status);
-const GList * gdm_address_peek_local_list (void);
-gboolean gdm_address_is_local (struct sockaddr_storage *sa);
-
-typedef struct {
- gboolean not_found; /* hostname below set to fallback,
- as gethostbyaddr/name failed */
- char *hostname; /* never a bogus dot, if
- invalid/unknown, then set to the
- ip address in string form */
-
- struct sockaddr_storage *addrs;
- int addr_count;
-} GdmHostent;
-
-GdmHostent * gdm_gethostbyname (const char *name);
-
-GdmHostent *gdm_gethostbyaddr (struct sockaddr_storage *ia);
-GdmHostent * gdm_hostent_copy (GdmHostent *he);
-void gdm_hostent_free (GdmHostent *he);
-
gboolean gdm_setup_gids (const char *login, gid_t gid);
void gdm_desetuid (void);
gboolean gdm_test_opt (const char *cmd, const char *help, const char *option);
-void gdm_close_all_descriptors (int from, int except, int except2);
-
-int gdm_open_dev_null (mode_t mode);
-
void gdm_unset_signals (void);
void gdm_saveenv (void);
@@ -93,11 +57,6 @@ const char * gdm_saved_getenv (const char *var);
/* leaks */
void gdm_restoreenv (void);
-/* like fopen with "w" but unlinks and uses O_EXCL */
-FILE * gdm_safe_fopen_w (const char *file, mode_t perm);
-/* like fopen with "a+" and uses O_EXCL and O_NOFOLLOW */
-FILE * gdm_safe_fopen_ap (const char *file, mode_t perm);
-
/* first must get initial limits before attempting to ever reset those
limits */
void gdm_get_initial_limits (void);
@@ -106,28 +65,8 @@ void gdm_reset_locale (void);
const char *gdm_root_user (void);
-#include <setjmp.h>
-
-/* stolen from xdm sources */
-#if defined(X_NOT_POSIX) || defined(__EMX__) || defined(__NetBSD__) && defined(__sparc__)
-#define Setjmp(e) setjmp(e)
-#define Longjmp(e,v) longjmp(e,v)
-#define Jmp_buf jmp_buf
-#else
-#define Setjmp(e) sigsetjmp(e,1)
-#define Longjmp(e,v) siglongjmp(e,v)
-#define Jmp_buf sigjmp_buf
-#endif
-
-void gdm_signal_ignore (int signal);
-void gdm_signal_default (int signal);
-
void gdm_sleep_no_signal (int secs);
-/* somewhat like g_build_filename, but does somet hing like
- * <dir> "/" <name> <extension>
- */
-char * gdm_make_filename (const char *dir, const char *name, const char *extension);
char * gdm_ensure_extension (const char *name, const char *extension);
char * gdm_strip_extension (const char *name, const char *extension);
@@ -142,34 +81,4 @@ const char * gdm_console_translate (const char *str);
gchar * gdm_read_default (gchar *key);
-#define NEVER_FAILS_seteuid(uid) \
- { int r = 0; \
- if (geteuid () != uid) \
- r = seteuid (uid); \
- if G_UNLIKELY (r != 0) \
- gdm_fail ("GDM file %s: line %d (%s): Cannot run seteuid to %d: %s", \
- __FILE__, \
- __LINE__, \
- G_GNUC_PRETTY_FUNCTION, \
- (int)uid, \
- strerror (errno)); }
-#define NEVER_FAILS_setegid(gid) \
- { int r = 0; \
- if (getegid () != gid) \
- r = setegid (gid); \
- if G_UNLIKELY (r != 0) \
- gdm_fail ("GDM file %s: line %d (%s): Cannot run setegid to %d: %s", \
- __FILE__, \
- __LINE__, \
- G_GNUC_PRETTY_FUNCTION, \
- (int)gid, \
- strerror (errno)); }
-
-/* first goes to euid-root and then sets the egid and euid, to make sure
- * this succeeds */
-#define NEVER_FAILS_root_set_euid_egid(uid,gid) \
- { NEVER_FAILS_seteuid (0); \
- NEVER_FAILS_setegid (gid); \
- if (uid != 0) { NEVER_FAILS_seteuid (uid); } }
-
#endif /* GDM_MISC_H */
diff --git a/daemon/server.h b/daemon/server.h
index 2bcc9c15..418018ae 100644
--- a/daemon/server.h
+++ b/daemon/server.h
@@ -23,21 +23,6 @@
#include "display.h"
-typedef struct _GdmXserver GdmXserver;
-
-struct _GdmXserver
-{
- char *id;
- char *name;
- char *command;
- gboolean flexible;
- gboolean choosable; /* not implemented yet */
- gboolean chooser; /* instead of greeter, run chooser */
- gboolean handled;
- int number;
- int priority;
-};
-
/* These are the servstat values, also used as server
* process exit codes */
#define SERVER_TIMEOUT 2 /* Server didn't start */
@@ -72,5 +57,3 @@ GdmXserver * gdm_server_resolve (GdmDisplay *disp);
#endif /* GDM_SERVER_H */
-
-/* EOF */
diff --git a/daemon/slave-main.c b/daemon/slave-main.c
new file mode 100644
index 00000000..b5ae04fc
--- /dev/null
+++ b/daemon/slave-main.c
@@ -0,0 +1,140 @@
+/* -*- 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 <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-log.h"
+#include "gdm-slave.h"
+
+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 void
+setup_signal_handlers (void)
+{
+ /* FIXME */
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GMainLoop *loop;
+ GOptionContext *context;
+ DBusGConnection *connection;
+ int ret;
+ GdmSlave *slave;
+ static char *display_id = NULL;
+ 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, "");
+
+ ret = 1;
+
+ 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);
+ }
+
+ setup_signal_handlers ();
+
+ slave = gdm_slave_new (display_id);
+
+ if (slave == NULL) {
+ goto out;
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ gdm_slave_start (slave);
+
+ g_main_loop_run (loop);
+
+ if (slave != NULL) {
+ g_object_unref (slave);
+ }
+
+ g_main_loop_unref (loop);
+
+ ret = 0;
+
+ out:
+
+ return ret;
+}
diff --git a/daemon/slave.c b/daemon/slave.c
index 268d6af9..6ded39da 100644
--- a/daemon/slave.c
+++ b/daemon/slave.c
@@ -156,12 +156,6 @@ static GSList *slave_waitpids = NULL;
extern gboolean gdm_first_login;
-/* The slavepipe (like fifo) connection, this is the write end */
-extern int slave_fifo_pipe_fd;
-
-/* wait for a GO in the SOP protocol */
-extern gboolean gdm_wait_for_go;
-
typedef struct {
pid_t pid;
} GdmWaitPid;
@@ -1442,7 +1436,7 @@ gdm_slave_run (GdmDisplay *display)
/* Really this will only be useful for the first local server,
since that's the only time this can really be on */
- while G_UNLIKELY (gdm_wait_for_go) {
+ while G_UNLIKELY (d->wait_for_go) {
struct timeval tv;
/* Wait 1 second. */
tv.tv_sec = 1;
@@ -1824,7 +1818,7 @@ run_config (GdmDisplay *display, struct passwd *pwent)
gdm_log_shutdown ();
- gdm_close_all_descriptors (0 /* from */, slave_fifo_pipe_fd /* except */, d->slave_notify_fd /* except2 */);
+ gdm_close_all_descriptors (0 /* from */, d->slave_notify_fd /* except */, -1 /* except2 */);
/* No error checking here - if it's messed the best response
* is to ignore & try to continue */
@@ -2574,7 +2568,7 @@ gdm_slave_greeter (void)
gdm_log_shutdown ();
- gdm_close_all_descriptors (2 /* from */, slave_fifo_pipe_fd/* except */, d->slave_notify_fd/* except2 */);
+ gdm_close_all_descriptors (2 /* from */, d->slave_notify_fd /* except */, -1 /* except2 */);
gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
@@ -2817,33 +2811,22 @@ gdm_slave_send (const char *str, gboolean wait_for_ack)
gdm_ack_response = NULL;
}
- /* ensure this is sent from the actual slave with the pipe always, this is anal I know */
- if (G_LIKELY (d->slavepid == getppid ()) || G_LIKELY (d->slavepid == getpid ())) {
- fd = slave_fifo_pipe_fd;
- } else {
- fd = -1;
- }
+ fd = -1;
- if G_UNLIKELY (fd < 0) {
- /* FIXME: This is not likely to ever be used, remove
- at some point. Other then slaves shouldn't be using
- these functions. And if the pipe creation failed
- in main daemon just abort the main daemon. */
- /* Use the fifo as a fallback only now that we have a pipe */
- fifopath = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR),
- ".gdmfifo", NULL);
- old = geteuid ();
- if (old != 0)
- seteuid (0);
+ fifopath = g_build_filename (gdm_daemon_config_get_value_string (GDM_KEY_SERV_AUTHDIR),
+ ".gdmfifo",
+ NULL);
+ old = geteuid ();
+ if (old != 0)
+ seteuid (0);
#ifdef O_NOFOLLOW
- VE_IGNORE_EINTR (fd = open (fifopath, O_WRONLY|O_NOFOLLOW));
+ VE_IGNORE_EINTR (fd = open (fifopath, O_WRONLY|O_NOFOLLOW));
#else
- VE_IGNORE_EINTR (fd = open (fifopath, O_WRONLY));
+ VE_IGNORE_EINTR (fd = open (fifopath, O_WRONLY));
#endif
- if (old != 0)
- seteuid (old);
- g_free (fifopath);
- }
+ if (old != 0)
+ seteuid (old);
+ g_free (fifopath);
/* eek */
if G_UNLIKELY (fd < 0) {
@@ -2854,9 +2837,7 @@ gdm_slave_send (const char *str, gboolean wait_for_ack)
gdm_fdprintf (fd, "\n%s\n", str);
- if G_UNLIKELY (fd != slave_fifo_pipe_fd) {
- VE_IGNORE_EINTR (close (fd));
- }
+ VE_IGNORE_EINTR (close (fd));
#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
if (wait_for_ack && ! gdm_got_ack) {
@@ -3059,7 +3040,7 @@ gdm_slave_chooser (void)
gdm_log_shutdown ();
VE_IGNORE_EINTR (close (0));
- gdm_close_all_descriptors (2 /* from */, slave_fifo_pipe_fd /* except */, d->slave_notify_fd /* except2 */);
+ gdm_close_all_descriptors (2 /* from */, d->slave_notify_fd /* except */, -1 /* except2 */);
gdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
@@ -3703,7 +3684,7 @@ session_child_run (struct passwd *pwent,
gdm_log_shutdown ();
- gdm_close_all_descriptors (3 /* from */, slave_fifo_pipe_fd /* except */, d->slave_notify_fd /* except2 */);
+ gdm_close_all_descriptors (3 /* from */, d->slave_notify_fd /* except */, -1 /* except2 */);
gdm_log_init ();
@@ -4973,7 +4954,7 @@ gdm_slave_handle_usr2_message (void)
}
}
} else if (strcmp (&s[1], GDM_NOTIFY_GO) == 0) {
- gdm_wait_for_go = FALSE;
+ d->wait_for_go = FALSE;
} else if (strcmp (&s[1], GDM_NOTIFY_TWIDDLE_POINTER) == 0) {
gdm_twiddle_pointer (d);
}
diff --git a/daemon/xdmcp.c b/daemon/xdmcp.c
deleted file mode 100644
index 2a07efe7..00000000
--- a/daemon/xdmcp.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * GDM - The GNOME Display Manager
- * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
- *
- * 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 <glib.h>
-#include <glib/gi18n.h>
-
-#include "display.h"
-#include "gdm-daemon-config.h"
-#include "gdm-log.h"
-
-#include "gdm-xdmcp-manager.h"
-#include "xdmcp.h"
-
-#ifdef HAVE_LIBXDMCP
-
-static GdmXdmcpManager *xdmcp_manager = NULL;
-
-gboolean
-gdm_xdmcp_init (void)
-{
- xdmcp_manager = gdm_xdmcp_manager_new ();
- return TRUE;
-}
-
-void
-gdm_xdmcp_run (void)
-{
- if (xdmcp_manager != NULL) {
- gdm_xdmcp_manager_start (xdmcp_manager, NULL);
- }
-}
-
-void
-gdm_xdmcp_close (void)
-{
- g_object_unref (xdmcp_manager);
-}
-
-static void
-reconnect_to_parent (GdmDisplay *to)
-{
- GError *error;
- gchar *command_argv[10];
- const gchar *proxyreconnect = gdm_daemon_config_get_value_string (GDM_KEY_XDMCP_PROXY_RECONNECT);
-
- command_argv[0] = (char *)proxyreconnect;
- command_argv[1] = "--display";
- command_argv[2] = to->parent_disp;
- command_argv[3] = "--display-authfile";
- command_argv[4] = to->parent_auth_file;
- command_argv[5] = "--to";
- command_argv[6] = to->name;
- command_argv[7] = "--to-authfile";
- command_argv[8] = to->authfile;
- command_argv[9] = NULL;
-
- gdm_debug ("XDMCP: migrating display by running "
- "'%s --display %s --display-authfile %s --to %s --to-authfile %s'",
- proxyreconnect,
- to->parent_disp, to->parent_auth_file,
- to->name, to->authfile);
-
- error = NULL;
- if (!g_spawn_async (NULL, command_argv, NULL, 0, NULL, NULL, NULL, &error)) {
- gdm_error (_("%s: Failed to run "
- "'%s --display %s --display-authfile %s --to %s --to-authfile %s': %s"),
- "gdm_xdmcp_migrate",
- proxyreconnect,
- to->parent_disp, to->parent_auth_file,
- to->name, to->authfile,
- error->message);
- g_error_free (error);
- }
-}
-
-void
-gdm_xdmcp_migrate (GdmDisplay *from, GdmDisplay *to)
-{
- if (from->type != TYPE_XDMCP_PROXY ||
- to->type != TYPE_XDMCP_PROXY)
- return;
- g_free (to->parent_disp);
- to->parent_disp = from->parent_disp;
- from->parent_disp = NULL;
-
- g_free (to->parent_auth_file);
- to->parent_auth_file = from->parent_auth_file;
- from->parent_auth_file = NULL;
-
- reconnect_to_parent (to);
-}
-
-#else /* HAVE_LIBXDMCP */
-
-/* Here come some empty stubs for no XDMCP support */
-int
-gdm_xdmcp_init (void)
-{
- gdm_error (_("%s: No XDMCP support"), "gdm_xdmcp_init");
- return FALSE;
-}
-
-void
-gdm_xdmcp_run (void)
-{
- gdm_error (_("%s: No XDMCP support"), "gdm_xdmcp_run");
-}
-
-void
-gdm_xdmcp_close (void)
-{
- gdm_error (_("%s: No XDMCP support"), "gdm_xdmcp_close");
-}
-
-void
-gdm_xdmcp_migrate (GdmDisplay *from, GdmDisplay *to)
-{
- gdm_error (_("%s: No XDMCP support"), "gdm_xdmcp_migrate");
-}
-
-#endif /* HAVE_LIBXDMCP */
diff --git a/daemon/xdmcp.h b/daemon/xdmcp.h
deleted file mode 100644
index d9870ffd..00000000
--- a/daemon/xdmcp.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * GDM - The GNOME Display Manager
- * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
- *
- * 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_XDMCP_H
-#define GDM_XDMCP_H
-
-/* Note that these are defined as empty stubs if there is no XDMCP support */
-gboolean gdm_xdmcp_init (void);
-void gdm_xdmcp_run (void);
-void gdm_xdmcp_close (void);
-
-void gdm_xdmcp_migrate (GdmDisplay *from, GdmDisplay *to);
-
-#endif /* GDM_XDMCP_H */
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 00000000..2693503c
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,12 @@
+NULL =
+
+dbusconfdir = $(DBUS_SYS_DIR)
+dbusconf_DATA = gdm.conf
+
+EXTRA_DIST = \
+ $(dbusconf_DATA) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
diff --git a/data/gdm.conf b/data/gdm.conf
new file mode 100644
index 00000000..a3881dc7
--- /dev/null
+++ b/data/gdm.conf
@@ -0,0 +1,31 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- Only root can own the service -->
+ <policy user="root">
+ <allow own="org.gnome.DisplayManager"/>
+
+ <allow send_interface="org.gnome.DisplayManager.Manager"/>
+ <allow send_interface="org.gnome.DisplayManager.Display"/>
+ <allow send_destination="org.gnome.DisplayManager"
+ send_interface="org.gnome.DBus.Properties" />
+ </policy>
+
+ <!-- Allow anyone to invoke methods on the interfaces -->
+ <policy context="default">
+ <allow send_interface="org.gnome.DisplayManager.Manager"/>
+ <allow send_interface="org.gnome.DisplayManager.Display"/>
+ <deny send_destination="org.gnome.DisplayManager"
+ send_interface="org.gnome.DBus.Properties" />
+ </policy>
+
+ <policy user="gdm">
+ <allow send_interface="org.gnome.DisplayManager.Manager"/>
+ <allow send_interface="org.gnome.DisplayManager.Display"/>
+ <allow send_destination="org.gnome.DisplayManager"
+ send_interface="org.gnome.DBus.Properties" />
+ </policy>
+
+</busconfig>
diff --git a/gui/gdmconfig.c b/gui/gdmconfig.c
index 90f43c9d..bfe84d5f 100644
--- a/gui/gdmconfig.c
+++ b/gui/gdmconfig.c
@@ -34,8 +34,6 @@
#include "gdm-common.h"
-#include "server.h"
-
static GHashTable *int_hash = NULL;
static GHashTable *bool_hash = NULL;
static GHashTable *string_hash = NULL;
diff --git a/gui/gdmconfig.h b/gui/gdmconfig.h
index 44044931..652186f4 100644
--- a/gui/gdmconfig.h
+++ b/gui/gdmconfig.h
@@ -25,6 +25,33 @@
#include "glib.h"
+typedef struct _GdmXserver GdmXserver;
+struct _GdmXserver
+{
+ char *id;
+ char *name;
+ char *command;
+ gboolean flexible;
+ gboolean choosable; /* not implemented yet */
+ gboolean chooser; /* instead of greeter, run chooser */
+ gboolean handled;
+ int number;
+ int priority;
+};
+
+#define DISPLAY_REMANAGE 2 /* Restart display */
+#define DISPLAY_ABORT 4 /* Houston, we have a problem */
+#define DISPLAY_REBOOT 8 /* Rebewt */
+#define DISPLAY_HALT 16 /* Halt */
+#define DISPLAY_SUSPEND 17 /* Suspend (don't use, use the interrupt) */
+#define DISPLAY_CHOSEN 20 /* successful chooser session,
+ restart display */
+#define DISPLAY_RUN_CHOOSER 30 /* Run chooser */
+#define DISPLAY_XFAILED 64 /* X failed */
+#define DISPLAY_GREETERFAILED 65 /* greeter failed (crashed) */
+#define DISPLAY_RESTARTGREETER 127 /* Restart greeter */
+#define DISPLAY_RESTARTGDM 128 /* Restart GDM */
+
void gdm_config_never_cache (gboolean never_cache);
void gdm_config_set_comm_retries (int tries);
gchar * gdm_config_get_string (const gchar *key);