Bug#291081: tsclient: XDMCP option assumes display :1 is free and
fails
Joachim Nilsson
Joachim Nilsson <joachim.nilsson@member.fsf.org>,
291081@bugs.debian.org
Tue, 18 Jan 2005 17:03:41 +0100
This is a multi-part MIME message sent by reportbug.
--===============1710534465==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Package: tsclient
Version: 0.132-2
Severity: normal
Tags: patch
tsclient assumes that display :1 is free when using the
XDMCP option to start Xnest.
Included in this report is a patch with a function stolen
from gdm-2.6.0.6:daemon/misc.c:gdm_get_free_display(). The
function tsc_get_free_display() has been adapted to tsclient
by removing all gdm specific code and should work for all
types of use cases.
Regards
/Jocke
-- System Information:
Debian Release: 3.1
APT prefers testing
APT policy: (500, 'testing')
Architecture: i386 (i686)
Kernel: Linux 2.6.8-1-k7
Locale: LANG=sv_SE.ISO-8859-15, LC_CTYPE=sv_SE.ISO-8859-15 (charmap=ISO-8859-15)
Versions of packages tsclient depends on:
ii libart-2.0-2 2.3.16-6 Library of functions for 2D graphi
ii libatk1.0-0 1.8.0-4 The ATK accessibility toolkit
ii libbonobo2-0 2.8.0-4 Bonobo CORBA interfaces library
ii libbonoboui2-0 2.8.0-2 The Bonobo UI library
ii libc6 2.3.2.ds1-20 GNU C Library: Shared libraries an
ii libgconf2-4 2.8.1-4 GNOME configuration database syste
ii libglib2.0-0 2.4.8-1 The GLib library of C routines
ii libgnome2-0 2.8.0-6 The GNOME 2 library - runtime file
ii libgnomecanvas2-0 2.8.0-1 A powerful object-oriented display
ii libgnomeui-0 2.8.0-3 The GNOME 2 libraries (User Interf
ii libgnomevfs2-0 2.8.3-8 The GNOME virtual file-system libr
ii libgtk2.0-0 2.4.14-2 The GTK+ graphical user interface
ii libice6 4.3.0.dfsg.1-10 Inter-Client Exchange library
ii liborbit2 1:2.10.2-1.1 libraries for ORBit2 - a CORBA ORB
ii libpanel-applet2-0 2.8.2-1 Library for GNOME 2 Panel applets
ii libpango1.0-0 1.6.0-3 Layout and rendering of internatio
ii libpopt0 1.7-5 lib for parsing cmdline parameters
ii libsm6 4.3.0.dfsg.1-10 X Window System Session Management
ii libxml2 2.6.11-5 GNOME XML library
ii rdesktop 1.3.1-1.1 RDP client for Windows NT/2000 Ter
ii xlibs 4.3.0.dfsg.1-10 X Keyboard Extension (XKB) configu
ii zlib1g 1:1.2.2-3 compression library - runtime
-- no debconf information
--===============1710534465==
Content-Type: text/x-c; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="patch-tsclient-0.132-get_free_display.diff"
--- support.c 2003-11-09 08:12:17.000000000 +0100
+++ support_new.c 2005-01-18 16:49:48.000000000 +0100
@@ -1,4 +1,3 @@
-
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -23,9 +22,23 @@
#include <dirent.h>
#include <fcntl.h>
+#include <arpa/inet.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+
#include "rdpfile.h"
#include "support.h"
+/* Stolen from jirka's vicious lib */
+#define VE_IGNORE_EINTR(expr) \
+ do { \
+ errno = 0; \
+ expr; \
+ } while G_UNLIKELY (errno == EINTR);
+
GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name) {
GtkWidget *parent, *found_widget;
@@ -188,6 +201,124 @@
}
+/**
+ * tsc_get_free_display
+ * @start: Start at this display, use 0 as safe value.
+ * @server_uid: UID of X server
+ *
+ * Evil function to figure out which display number is free.
+ *
+ * Stolen from gdm-2.6.0:daemon/misc.c
+ *
+ * Returns: A free X display number or -1 on failure.
+ */
+
+int tsc_get_free_display (int start, uid_t server_uid)
+{
+ int sock;
+ int i;
+ struct sockaddr_in serv_addr = {0};
+
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ /* Cap this at 3000, I'm not sure we can ever seriously
+ * go that far */
+ for (i = start; i < 3000; i ++) {
+ struct stat s;
+ char buf[256];
+ FILE *fp;
+ int r;
+
+#ifdef ENABLE_IPV6
+ if (have_ipv6 ()) {
+ struct sockaddr_in6 serv6_addr= {0};
+
+ sock = socket (AF_INET6, SOCK_STREAM,0);
+
+ serv6_addr.sin6_family = AF_INET6;
+ serv6_addr.sin6_addr = in6addr_loopback;
+ serv6_addr.sin6_port = htons (6000 + i);
+ errno = 0;
+ VE_IGNORE_EINTR (connect (sock,
+ (struct sockaddr *)&serv6_addr,
+ sizeof (serv6_addr)));
+ }
+ else
+#endif
+ {
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+
+ serv_addr.sin_port = htons (6000 + i);
+
+ errno = 0;
+ VE_IGNORE_EINTR (connect (sock,
+ (struct sockaddr *)&serv_addr,
+ sizeof (serv_addr)));
+ }
+ if (errno != 0 && errno != ECONNREFUSED) {
+ VE_IGNORE_EINTR (close (sock));
+ continue;
+ }
+ VE_IGNORE_EINTR (close (sock));
+
+ /* if lock file exists and the process exists */
+ g_snprintf (buf, sizeof (buf), "/tmp/.X%d-lock", i);
+ VE_IGNORE_EINTR (r = stat (buf, &s));
+ if (r == 0 &&
+ ! S_ISREG (s.st_mode)) {
+ /* Eeeek! not a regular file? Perhaps someone
+ is trying to play tricks on us */
+ continue;
+ }
+ VE_IGNORE_EINTR (fp = fopen (buf, "r"));
+ if (fp != NULL) {
+ char buf2[100];
+ char *getsret;
+ VE_IGNORE_EINTR (getsret = fgets (buf2, sizeof (buf2), fp));
+ if (getsret != NULL) {
+ gulong pid;
+ if (sscanf (buf2, "%lu", &pid) == 1 &&
+ kill (pid, 0) == 0) {
+ VE_IGNORE_EINTR (fclose (fp));
+ continue;
+ }
+
+ }
+ VE_IGNORE_EINTR (fclose (fp));
+
+ /* whack the file, it's a stale lock file */
+ VE_IGNORE_EINTR (unlink (buf));
+ }
+
+ /* if starting as root, we'll be able to overwrite any
+ * stale sockets or lock files, but a user may not be
+ * able to */
+ if (server_uid > 0) {
+ g_snprintf (buf, sizeof (buf),
+ "/tmp/.X11-unix/X%d", i);
+ VE_IGNORE_EINTR (r = stat (buf, &s));
+ if (r == 0 &&
+ s.st_uid != server_uid) {
+ continue;
+ }
+
+ g_snprintf (buf, sizeof (buf),
+ "/tmp/.X%d-lock", i);
+ VE_IGNORE_EINTR (r = stat (buf, &s));
+ if (r == 0 &&
+ s.st_uid != server_uid) {
+ continue;
+ }
+ }
+
+ return i;
+ }
+
+ return -1;
+}
+
+
/***************************************
* *
* tsc_launch_remote *
@@ -469,6 +600,7 @@
c_argv[c_argc++] = g_strdup (buffer);
} else if (rdp->protocol == 2) {
+ int display;
if (g_find_program_in_path ("Xnest")) {
sflags += G_SPAWN_SEARCH_PATH;
@@ -480,7 +612,13 @@
return 1;
}
- sprintf(buffer, ":1");
+ /* Starting search from :1 (assuming we run at :0) */
+ display = tsc_get_free_display (1, getuid());
+ if (-1 == display) {
+ tsc_error_message (_("Could not find a free X display."));
+ return 1;
+ }
+ sprintf(buffer, ":%d", display);
c_argv[c_argc++] = strdup(buffer);
sprintf(buffer, "-once");
--===============1710534465==--