-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Edit : 2025-1-7 The problem symptoms have been edited. Please consult the issue history for where we started.
xrdp version
0.10.x / devel
Detailed xrdp version, build options
xrdp 0.10.80
A Remote Desktop Protocol Server.
Copyright (C) 2004-2024 Jay Sorg, Neutrino Labs, and all contributors.
See https://github.com/neutrinolabs/xrdp for more information.
Configure options:
--enable-devel-all
--enable-fuse
--enable-pixman
--enable-ipv6
--enable-painter
--enable-jpeg
--with-imlib2
--enable-vsock
--with-freetype2
--enable-utmp
CC=clang
CFLAGS=-g
LDFLAGS=-L/usr/local/lib
CPPFLAGS=-I/usr/local/include
Compiled with OpenSSL 3.0.15 3 Sep 2024
Operating system & version
FreeBSD 14.2-RELEASE
Installation method
git clone & make install
Which backend do you use?
xorgxrdp
What desktop environment do you use?
XFCE
Environment xrdp running on
VM
What's your client?
Various
Area(s) with issue?
Session manager (sesman)
Steps to reproduce
- Ensure sshd is configured to allow X11 forwarding
- Log on to system from elsewhere using
ssh -X
:-
$ ssh -X freebsd14.test.lan
<snipped>
$ echo $DISPLAY
localhost:10
$ xauth list
freebsd14/unix:10 MIT-MAGIC-COOKIE-1 186a734d1d0ea2b8a2ae0c543a50c7c
- Log in to system using xrdp and the same user
✔️ Expected Behavior
Following login, xauth list
in ssh session shows same information
❌ Actual Behavior
$ xauth list
freebsd14/unix:10 MIT-MAGIC-COOKIE-1 00615f25c6bb6e0c71b20c32d4e9ea12
Anything else?
Thanks to @derekschrock for raising this on Gitter.
An active X server is checked for by xrdp by using the following algorithm:-
- Looking for the UNIX Domain Socket opened by the X server
- trying to bind to
0.0.0.0:<tport>
and/or[::]:<tport>
where<tport>
is the TCP port which may be used by the X server.
When ssh X11 forwarding is used by ssh
, there is no Unix Domain Socket, and the forwarding TCP port is bound to localhost
only.
The problem seems to be caused by a difference in behaviour between Linux and FreeBSD when SO_REUSEADDR
is set on a TCP socket passed to bind()
On Linux, if a program is listening on localhost:<tport>
, and another user tries to listen on 0.0.0.0:<tport>;
or [::]:<tport>
, the bind()
fails with EADDRINUSE
On FreeBSD, with the same conditions, the bind()
succeeds.
The following IPv4 test program illustrates the issue:-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
static unsigned short
get_port(void)
{
unsigned short rv = 0;
const char *d = getenv("DISPLAY");
if (d == NULL || strncmp(d, "localhost:", 10) != 0)
{
fprintf(stderr, "DISPLAY is not set by ssh\n");
}
else
{
rv = atoi(d + 10);
if (rv == 0)
{
fprintf(stderr, "Unable to get port number from DISPLAY\n");
}
else
{
rv += 6000;
}
}
return rv;
}
static int
g_tcp_socket(void)
{
int option;
int sck = (int)socket(AF_INET, SOCK_STREAM, 0);
if (sck >= 0)
{
option = 1;
if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&option,
sizeof(option)) < 0)
{
perror("setsockopt");
close(sck);
sck = -1;
}
}
else
{
perror("socket");
}
return sck;
}
static int
g_tcp_bind_address(int sck, unsigned short port, unsigned int addr)
{
int rv;
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_addr.s_addr = htonl(addr);
s.sin_port = htons(port);
rv = bind(sck, (struct sockaddr *)&s, sizeof(s));
if (rv < 0)
{
char msg[64];
char addrstr[32];
const char *paddr;
switch (addr)
{
case INADDR_ANY:
paddr = "INADDR_ANY";
break;
default:
snprintf(addrstr, sizeof(addrstr), "%08X", addr);
paddr = addrstr;
}
snprintf(msg, sizeof(msg), "bind addr=%s port=%hu", paddr, port);
perror(msg);
}
return rv;
}
int main()
{
unsigned short port = get_port();
if (port > 0)
{
int sck = g_tcp_socket();
if (sck >= 0)
{
if (g_tcp_bind_address(sck, port, INADDR_ANY) == 0)
{
printf("Bound successfully to port %hu on INADDR_ANY\n", port);
}
close(sck);
}
}
}
Log in to Linux or FreeBSD over ssh with X11 forwarding and run the program.
On Linux:-
$ ./temp
bind addr=INADDR_ANY port=6010: Address already in use
On FreeBSD:-
$ ./temp
Bound successfully to port 6010 on INADDR_ANY