summaryrefslogtreecommitdiff
path: root/xfce4-session/ice-layer.c
diff options
context:
space:
mode:
authorBenedikt Meurer <benny@xfce.org>2003-07-07 17:27:36 +0000
committerBenedikt Meurer <benny@xfce.org>2003-07-07 17:27:36 +0000
commit6576008411b5b3c6c8c5caaf5b2ccb2719814039 (patch)
tree393b04df00d6f520fe1bdb868b175461be966b9e /xfce4-session/ice-layer.c
parent925bdc32ccff6fd375be19c40e8fde2435008642 (diff)
downloadxfce4-session-6576008411b5b3c6c8c5caaf5b2ccb2719814039.tar.gz
Initial revisionBMEURER_20030707
(Old svn revision: 4420)
Diffstat (limited to 'xfce4-session/ice-layer.c')
-rw-r--r--xfce4-session/ice-layer.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/xfce4-session/ice-layer.c b/xfce4-session/ice-layer.c
new file mode 100644
index 00000000..14600c5a
--- /dev/null
+++ b/xfce4-session/ice-layer.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2003 Benedikt Meurer <benedikt.meurer@unix-ag.uni-siegen.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <X11/ICE/ICElib.h>
+#include <X11/ICE/ICEutil.h>
+#include <X11/SM/SMlib.h>
+
+#include <glib.h>
+
+#include "client.h"
+#include "ice-layer.h"
+#include "manager.h"
+
+/* prototypes */
+static void ice_error_handler(IceConn);
+static gboolean ice_process_messages(GIOChannel *, GIOCondition, IceConn);
+static gboolean ice_connection_accept(GIOChannel *, GIOCondition, IceListenObj);
+static FILE *ice_tmpfile(char **);
+static void ice_auth_add(FILE *, FILE *, char *, IceListenObj);
+static void ice_cleanup(void);
+
+/* ICE authority cleanup file name */
+static char *authCleanupFile;
+
+/*
+ * ICE host based authentication proc
+ */
+Bool
+ice_auth_proc(char *hostname)
+{
+ return(False);
+}
+
+/*
+ * ICE I/O error handler
+ */
+static void
+ice_error_handler(IceConn iceConn)
+{
+ /*
+ * The I/O error handlers does whatever is necessary to respond
+ * to the I/O error and then returns, but it does not call
+ * IceCloseConnection. The ICE connection is given a "bad IO"
+ * status, and all future reads and writes to the connection
+ * are ignored. The next time IceProcessMessages is called it
+ * will return a status of IceProcessMessagesIOError. At that
+ * time, the application should call IceCloseConnection.
+ */
+ g_warning("ICE I/O error on connection %p", iceConn);
+}
+
+/*
+ * Process ICE messages
+ */
+static gboolean
+ice_process_messages(GIOChannel *channel, GIOCondition condition,
+ IceConn iceConn)
+{
+ IceProcessMessagesStatus status;
+ SmsConn smsConn;
+ GList *lp;
+
+ status = IceProcessMessages(iceConn, NULL, NULL);
+
+ if (status == IceProcessMessagesIOError) {
+ for (lp = g_list_first(clients); lp; lp = lp->next)
+ if (CLIENT(lp->data)->iceConn == iceConn)
+ break;
+
+ if (lp != NULL) {
+ smsConn = CLIENT(lp->data)->smsConn;
+ client_free(CLIENT(lp->data));
+ SmsCleanUp(smsConn);
+ clients = g_list_delete_link(clients, lp);
+ }
+
+ IceSetShutdownNegotiation(iceConn, False);
+ (void)IceCloseConnection(iceConn);
+
+ /* remove the I/O watch */
+ return(FALSE);
+ }
+
+ /* keep the I/O watch running */
+ return(TRUE);
+}
+
+/*
+ * ICE connection watch. This is called whenever a new ICE connection is
+ * made. It arranges for the ICE connection to be handled via the GLib
+ * main event loop.
+ */
+/* ARGSUSED */
+static void
+ice_connection_watch(IceConn iceConn, IcePointer clientData, Bool opening,
+ IcePointer *watchData)
+{
+ GIOChannel *channel;
+ guint watchID;
+ gint fd;
+
+ if (opening) {
+ fd = IceConnectionNumber(iceConn);
+
+ /*
+ * Make sure we don't pass on these file descriptors to an
+ * exec'd child process.
+ */
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+
+ /* create an I/O channel for the new client connection */
+ channel = g_io_channel_unix_new(fd);
+ watchID = g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_IN,
+ (GIOFunc)ice_process_messages, iceConn);
+ g_io_channel_unref(channel);
+
+ /* */
+ *watchData = (IcePointer)GUINT_TO_POINTER(watchID);
+ }
+ else {
+ /* remove the I/O source as the connection is going down */
+ g_source_remove(GPOINTER_TO_UINT(*watchData));
+ }
+}
+
+/*
+ * Accept new ICE connections
+ */
+static gboolean
+ice_connection_accept(GIOChannel *channel, GIOCondition condition,
+ IceListenObj iceListener)
+{
+ IceConnectStatus cstatus;
+ IceAcceptStatus astatus;
+ IceConn iceConn;
+
+ iceConn = IceAcceptConnection(iceListener, &astatus);
+
+ if (astatus != IceAcceptSuccess) {
+ g_warning("Failed to accept ICE connection on listener %p",
+ (void *)iceListener);
+ return(TRUE);
+ }
+
+ /* Wait for the connection to leave pending state */
+ do {
+#if 0 /* THIS MIGHT CAUSE A RACE CONDITIION ?!?! */
+ (void)g_main_context_iteration(NULL, TRUE);
+#else
+ (void)IceProcessMessages(iceConn, NULL, NULL);
+#endif
+ } while ((cstatus = IceConnectionStatus(iceConn)) == IceConnectPending);
+
+ if (cstatus != IceConnectAccepted) {
+ if (cstatus == IceConnectIOError) {
+ g_warning("I/O error opening ICE connection %p",
+ (void *)iceConn);
+ }
+ else {
+ g_warning("ICE connectio %p rejected", (void *)iceConn);
+ }
+
+ IceSetShutdownNegotiation(iceConn, False);
+ (void)IceCloseConnection(iceConn);
+ }
+
+ /* keep the listener watch running */
+ return(TRUE);
+}
+
+/*
+ */
+static FILE *
+ice_tmpfile(char **name)
+{
+ GError *error;
+ mode_t mode;
+ FILE *fp;
+ int fd;
+
+ fp = NULL;
+ mode = umask(0077);
+
+ if ((fd = g_file_open_tmp(".xfsm-ICE-XXXXXX", name, &error)) < 0) {
+ g_warning("Unable to open temporary file: %s", error->message);
+ g_error_free(error);
+ }
+ else
+ fp = fdopen(fd, "wb");
+
+ umask(mode);
+
+ return(fp);
+}
+
+/*
+ * for printing hex digits (taken from KDE3)
+ */
+static void
+fprintfhex(FILE *fp, int len, char *cp)
+{
+ static char hexchars[] = "0123456789abcdef";
+
+ for (; len > 0; len--, cp++) {
+ unsigned char s = *cp;
+ putc(hexchars[s >> 4], fp);
+ putc(hexchars[s & 0x0f], fp);
+ }
+}
+
+/*
+ */
+static void
+ice_auth_add(FILE *setupFp, FILE *cleanupFp, char *protocol,
+ IceListenObj iceListener)
+{
+ IceAuthDataEntry entry;
+
+ entry.protocol_name = protocol;
+ entry.network_id = IceGetListenConnectionString(iceListener);
+ entry.auth_name = "MIT-MAGIC-COOKIE-1";
+ entry.auth_data = IceGenerateMagicCookie(16);
+ entry.auth_data_length = 16;
+
+ IceSetPaAuthData(1, &entry);
+
+ fprintf(setupFp, "add %s \"\" %s MIT-MAGIC-COOKIE-1 ", protocol,
+ entry.network_id);
+ fprintfhex(setupFp, 16, entry.auth_data);
+ fprintf(setupFp, "\n");
+
+ fprintf(cleanupFp, "remove protoname=%s protodata=\"\" netid=%s "
+ "authname=MIT-MAGIC-COOKIE-1\n", protocol,
+ entry.network_id);
+
+ free(entry.network_id);
+ free(entry.auth_data);
+}
+
+/*
+ */
+gboolean
+ice_setup_listeners(int numListeners, IceListenObj *listenObjs)
+{
+ GIOChannel *channel;
+ char *authSetupFile;
+ gchar *command;
+ FILE *cleanupFp;
+ FILE *setupFp;
+ int fd;
+ int n;
+
+ /* */
+ IceSetIOErrorHandler(ice_error_handler);
+ IceAddConnectionWatch(ice_connection_watch, NULL);
+
+ if ((cleanupFp = ice_tmpfile(&authCleanupFile)) == NULL)
+ return(FALSE);
+
+ if ((setupFp = ice_tmpfile(&authSetupFile)) == NULL) {
+ (void)fclose(cleanupFp);
+ (void)unlink(authCleanupFile);
+ g_free(authCleanupFile);
+ return(FALSE);
+ }
+
+ for (n = 0; n < numListeners; n++) {
+ fd = IceGetListenConnectionNumber(listenObjs[n]);
+
+ /*
+ * Make sure we don't pass on these file descriptors to an
+ * exec'd child process.
+ */
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+
+ /* create an I/O channel for the new client connection */
+ channel = g_io_channel_unix_new(fd);
+ (void)g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_IN,
+ (GIOFunc)ice_connection_accept,
+ (gpointer)listenObjs[n]);
+ g_io_channel_unref(channel);
+
+ /* setup auth for this listener */
+ ice_auth_add(setupFp, cleanupFp, "ICE", listenObjs[n]);
+ ice_auth_add(setupFp, cleanupFp, "XSMP", listenObjs[n]);
+ IceSetHostBasedAuthProc(listenObjs[n], ice_auth_proc);
+ }
+
+ /* close ICE authority files */
+ (void)fclose(setupFp);
+ (void)fclose(cleanupFp);
+
+ /* setup ICE authority */
+ command = g_strdup_printf("iceauth source %s", authSetupFile);
+ system(command);
+ g_free(command);
+
+ /* remove the setup file, no longer needed */
+ unlink(authSetupFile);
+ g_free(authSetupFile);
+
+ /* remember to cleanup ICE stuff on exit() */
+ g_atexit(ice_cleanup);
+
+ return(TRUE);
+}
+
+/*
+ * Cleanup ICE stuff
+ */
+void
+ice_cleanup(void)
+{
+ gchar *command;
+
+ g_return_if_fail(authCleanupFile != NULL);
+
+ /* remove newly added ICE authority entries */
+ command = g_strdup_printf("iceauth source %s", authCleanupFile);
+ system(command);
+ g_free(command);
+
+ /* remove the cleanup file, no longer needed */
+ unlink(authCleanupFile);
+ g_free(authCleanupFile);
+}
+
+