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
--- 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");