[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1018240: Xtightvnc(1): support arbitrary stdio in -inetd, not just socket-based



Package: tightvncserver
Version: 1:1.3.10-5+b1
Severity: wishlist
Control: found -1 1:1.3.10-3

	[Please do not Cc: me, for I’m “on the list,” so to say, and
	I try to reserve my inbox for private communication only.
	I’d have set up Mail-Followup-To:, but there doesn’t seem to
	be a way to make it point to the report being filed.]

	Xtightvnc(1) concludes with:

    Probably, the best way to secure Xvnc server is to allow only
    loopback connections from the server machine (the -localhost option)
    and to use SSH tunneling for remote access to the Xvnc server.

	However, it’s arguably even more secure to either use a Unix
	socket accessible by only the intended user(s) (note that
	OpenSSH supports Unix to Unix, TCP to Unix, and Unix to TCP
	socket forwarding; see the -L option in ssh(1)); or a pair
	of pipes, such as rsync(1) uses (by essentially invoking
	$ ssh -- REMOTE rsync --server to access the remote.)

	Moreover, certain lightweight SSH2 servers, such as
	tinysshd(8), omit support for forwarding altogether, which
	doesn’t inconvenience tools such as rsync(1) in the least,
	but which makes the advice above impossible to follow.

	Unfortunately, the obvious candidate for such usage, the
	-inetd option, doesn’t quite support it.  The cause is
	twofold.  On the one hand, Xtightvnc -inetd still assumes
	that the communication is done via a TCP socket, uses
	setsockopt(2) on the file descriptor, and exits when that
	fails.  On the other, contrary to the documentation,

  -inetd
      Xvnc is launched by inetd.  This option causes Xvnc to redirect
      network input/output to stdin/stdout.

	the current implementation uses not stdin and stdout, but rather
	‘stdin’ only, for both input and output.  Which isn’t a problem
	when the server is started from inetd(8) proper, as in that case
	both stdin and stdout point to the same socket; but /is/ a
	problem in the proposed usage, where stdin and stdout are two
	separate pipes (incoming and outgoing, respectively.)

Xvnc/programs/Xserver/hw/vnc/init.c
361-           close stderr.  OsInit() will redirect stderr logging to an
362-           appropriate log file or /dev/null if that doesn't work. */
363-
364:	dup2(0,3);
365-	inetdSock = 3;
366-	close(2);
367-

Xvnc/programs/Xserver/hw/vnc/sockets.c
101-
102:	if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY,
103-		       (char *)&one, sizeof(one)) < 0) {
104:	    rfbLogPerror("setsockopt");
105-	    exit(1);
106-	}
107-

	(So far as I can tell only a single use of setsockopt(2)
	in the file is relevant to the problem being described.)

	As such, my suggestions would be as follows.

	 1. The setsockopt(2) failure in rfbInitSockets () is
	    downgraded to a warning (from a fatal error.)  This
	    alone should be sufficient for running Xtightvnc(1)
	    on a Unix socket via inetd(8), which is already more
	    secure than a localhost-bound TCP port.

	 2. In place of inetdSock, the code should use separate
	    inetdIn and inetdOut file descriptors, so that it’s
	    possible to use a pair of pipes in place of a socket.

	It’s also possible to work around the problem at hand by
	using socat(1) and strace(1) as follows.

#!/bin/sh
### tightvnc-ssh-pipe.sh
## Example Xtightvnc tunneling via SSH pipes.

## Connect with:
##   $ xvncviewer localhost::12345 

LOCAL_PORT=12345
REMOTE=remote.example.net

## .
exec socat TCP4-LISTEN:"$LOCAL_PORT",bind=localhost \
    EXEC:"ssh -t -- ${REMOTE} \
  set -C -e -u -- ; stty raw -echo ; exec 3<> /dev/tty ; \
  strace -o /tmp/debug.\"$(date +%s.%N)\" -ft -s95 \
  -e trace=dup2 -e trace=setsockopt \
  -e inject=setsockopt\\:retval=0\\:when=4 \
  -e inject=dup2\\:retval=3\\:when=1 \
  -- Xtightvnc \\:99 -auth \"\$HOME\"/.Xauthority \
         -geometry 1280x$((1024 - 2 * 24)) -depth 24 \
         -dontdisconnect -nevershared -inetd",pty

### tightvnc-ssh-pipe.sh ends here

	Here, ssh -t, together with the socat(1) ,pty option, forces
	pseudo-tty allocation on the remote side; exec 3<> /dev/tty
	redirects file descriptor 3 (which is the number inetdSock
	is set to) to the pty thus allocated; -e inject=dup2:retval=3
	:when=1 turns the dup2(2) call in init.c into a no-op; and
	-e inject=setsockopt:retval=0:when=4 does the same to the
	setsockopt(2) call in sockets.c.

	Also, while we’re at it, note that Xtightvnc above ignores the
	:99 option and binds to /tmp/.X11-unix/X1, as if :1 were given.

	It should be noted that the use of pipes, or actually -inetd
	/ inetd.conf(5) ‘nowait’, means that the failure of the
	underlying connection invariably leads to the termination
	of the associated X session.  (While with the VNC server
	possessing a listening socket, which is the default case,
	and also would’ve been one were Xtightvnc(1) to support ‘wait’
	inetd.conf(5) option, it’s possible to reconnect.)  IME in
	LAN environments, it’s an acceptable tradeoff.

	Ideally, this should be complemented by a -command option in
	xvncviewer(1), to access the remote server by starting the
	command given in place of opening a TCP connection directly
	(not unlike ssh_config(5) ProxyCommand option.)  But that
	deserves a separate report IMO. 

-- 
FSF associate member #7257  http://am-1.org/~ivan/


Reply to: