Package:  vnc4server
Version:  4.1.1+X4.3.0-37.1
Severity: wishlist
User:     debian-...@lists.debian.org
Usertags: debian-edu

It would be great and good for security if vnc4server supported using a
local unix socket to connect to VNC, when using VNC to provide several
desktops on the local machine.  It would get rid of the need for
password checking and leave access control to the unix file system
permissions.

My college Dag-Erling Smørgrav wrote a patch for tigervnc to do this.
Attaching it here for inspiration.

-- System Information:
Debian Release: 7.0
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: i386 (i686)

Kernel: Linux 3.2.0-4-686-pae (SMP w/1 CPU core)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages vnc4server depends on:
ii  libc6           2.13-38
ii  libgcc1         1:4.7.2-5
ii  libstdc++6      4.7.2-5
ii  libx11-6        2:1.5.0-1
ii  libxext6        2:1.3.1-2
ii  libxtst6        2:1.2.1-1
ii  x11-common      1:7.7+2
ii  xbase-clients   1:7.7+2
ii  xserver-common  2:1.12.4-6
ii  zlib1g          1:1.2.7.dfsg-13

Versions of packages vnc4server recommends:
ii  xfonts-base  1:1.0.3

Versions of packages vnc4server suggests:
pn  vnc-java  <none>

-- no debconf information
--- tigervnc-1.1.0.orig/common/network/CMakeLists.txt	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/CMakeLists.txt	2012-10-06 20:50:22.323954919 +0200
@@ -1,4 +1,5 @@
 include_directories(${CMAKE_SOURCE_DIR}/common)
 
 add_library(network STATIC
-  TcpSocket.cxx)
+  TcpSocket.cxx
+  UnixSocket.cxx)
--- tigervnc-1.1.0.orig/common/network/Makefile.am	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/Makefile.am	2012-10-06 20:50:22.323954919 +0200
@@ -2,7 +2,7 @@
 
 HDRS = Socket.h TcpSocket.h
 
-libnetwork_la_SOURCES = $(HDRS) TcpSocket.cxx
+libnetwork_la_SOURCES = $(HDRS) TcpSocket.cxx UnixSocket.cxx
 
 libnetwork_la_CPPFLAGS = -I$(top_srcdir)/common
 
--- tigervnc-1.1.0.orig/common/network/Socket.h	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/Socket.h	2012-10-06 20:50:22.324954919 +0200
@@ -95,6 +95,8 @@
     // if one is installed.  Otherwise, returns 0.
     virtual Socket* accept() = 0;
 
+    virtual int getMyPort() = 0;
+
     // setFilter() applies the specified filter to all new connections
     void setFilter(ConnectionFilter* f) {filter = f;}
     int getFd() {return fd;}
--- /dev/null	2012-09-20 14:39:17.551000000 +0200
+++ tigervnc-1.1.0/common/network/UnixSocket.cxx	2012-10-06 22:30:17.171973531 +0200
@@ -0,0 +1,233 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (c) 2012 University of Oslo.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <network/UnixSocket.h>
+#include <os/net.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+
+using namespace network;
+using namespace rdr;
+
+static rfb::LogWriter vlog("UnixSocket");
+
+// -=- Socket initialisation
+static bool socketsInitialised = false;
+static void initSockets() {
+  if (socketsInitialised)
+    return;
+  signal(SIGPIPE, SIG_IGN);
+  socketsInitialised = true;
+}
+
+
+// -=- UnixSocket
+
+UnixSocket::UnixSocket(int sock, bool close)
+  : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
+{
+}
+
+UnixSocket::UnixSocket(const char *path)
+  : closeFd(true)
+{
+  int sock, err, result;
+  sockaddr_un addr;
+  socklen_t salen;
+
+  if (strlen(path) >= sizeof(addr.sun_path))
+    throw SocketException("socket path is too long", ENAMETOOLONG);
+
+  // - Create a socket
+  initSockets();
+  sock = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sock == -1)
+    throw SocketException("unable to create socket", errno);
+
+  // - Attempt to connect
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, path);
+  salen = sizeof(addr);
+  while ((result = connect(sock, (sockaddr *)&addr, salen)) == -1) {
+    err = errno;
+    close(sock);
+    break;
+  }
+
+  if (result == -1)
+    throw SocketException("unable connect to socket", err);
+
+  // - By default, close the socket on exec()
+  fcntl(sock, F_SETFD, FD_CLOEXEC);
+
+  // Create the input and output streams
+  instream = new FdInStream(sock);
+  outstream = new FdOutStream(sock);
+  ownStreams = true;
+}
+
+UnixSocket::~UnixSocket() {
+  if (closeFd)
+    close(getFd());
+}
+
+int UnixSocket::getMyPort() {
+  return 0;
+}
+
+char* UnixSocket::getPeerAddress() {
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+
+  if (getpeername(getFd(), (struct sockaddr *)&addr, &salen) == 0)
+    return rfb::strDup(addr.sun_path);
+  else
+    return rfb::strDup("");
+}
+
+int UnixSocket::getPeerPort() {
+  return 0;
+}
+
+char* UnixSocket::getPeerEndpoint() {
+  return getPeerAddress();
+}
+
+bool UnixSocket::sameMachine() {
+  return true;
+}
+
+void UnixSocket::shutdown()
+{
+  Socket::shutdown();
+  ::shutdown(getFd(), 2);
+}
+
+bool UnixSocket::isSocket(int sock)
+{
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+  return getsockname(sock, (struct sockaddr *)&addr, &salen) >= 0;
+}
+
+bool UnixSocket::isConnected(int sock)
+{
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+  return getpeername(sock, (struct sockaddr *)&addr, &salen) >= 0;
+}
+
+UnixListener::UnixListener(const char *path, int mode,
+			 int sock, bool close_) : closeFd(close_)
+{
+  struct sockaddr_un addr;
+  mode_t saved_umask;
+  int err, result;
+
+  if (sock != -1) {
+    fd = sock;
+    return;
+  }
+
+  if (strlen(path) >= sizeof(addr.sun_path))
+    throw SocketException("socket path is too long", ENAMETOOLONG);
+
+  // - Create a socket
+  initSockets();
+  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+    throw SocketException("unable to create listening socket", errno);
+
+  // - By default, close the socket on exec()
+  fcntl(sock, F_SETFD, FD_CLOEXEC);
+
+  // - Delete existing socket (ignore result)
+  unlink(path);
+
+  // - Attempt to bind to the requested path
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, path);
+  saved_umask = umask(0777);
+  result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  err = errno;
+  umask(saved_umask);
+  if (result < 0) {
+    close(fd);
+    throw SocketException("unable to bind listening socket", err);
+  }
+
+  // - Set socket mode
+  if (chmod(path, mode) < 0) {
+    err = errno;
+    close(fd);
+    throw SocketException("unable to set socket mode", err);
+  }
+
+  // - Set it to be a listening socket
+  if (listen(fd, 5) < 0) {
+    err = errno;
+    close(fd);
+    throw SocketException("unable to set socket to listening mode", err);
+  }
+}
+
+UnixListener::~UnixListener() {
+  if (closeFd) close(fd);
+}
+
+void UnixListener::shutdown()
+{
+  ::shutdown(getFd(), 2);
+}
+
+
+Socket*
+UnixListener::accept() {
+  int new_sock = -1;
+
+  // Accept an incoming connection
+  if ((new_sock = ::accept(fd, 0, 0)) < 0)
+    throw SocketException("unable to accept new connection", errno);
+
+  // - By default, close the socket on exec()
+  fcntl(new_sock, F_SETFD, FD_CLOEXEC);
+
+  // - Create the socket object
+  return new UnixSocket(new_sock);
+}
+
+int UnixListener::getMyPort() {
+  return 0;
+}
--- /dev/null	2012-09-20 14:39:17.551000000 +0200
+++ tigervnc-1.1.0/common/network/UnixSocket.h	2012-10-06 20:50:22.325954919 +0200
@@ -0,0 +1,76 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (c) 2012 University of Oslo.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- UnixSocket.h - base-class for UNIX stream sockets.
+//     This header also defines the UnixListener class, used
+//     to listen for incoming socket connections over UNIX
+//
+//     NB: Any file descriptors created by the UnixSocket or
+//     UnixListener classes are close-on-exec if the OS supports
+//     it.  UnixSockets initialised with a caller-supplied fd
+//     are NOT set to close-on-exec.
+
+#ifndef __NETWORK_UNIX_SOCKET_H__
+#define __NETWORK_UNIX_SOCKET_H__
+
+#include <network/Socket.h>
+
+#include <list>
+
+namespace network {
+
+   class UnixSocket : public Socket {
+  public:
+    UnixSocket(int sock, bool close=true);
+    UnixSocket(const char *name);
+    virtual ~UnixSocket();
+
+    virtual int getMyPort();
+
+    virtual char* getPeerAddress();
+    virtual int getPeerPort();
+    virtual char* getPeerEndpoint();
+    virtual bool sameMachine();
+
+    virtual void shutdown();
+
+    static bool isSocket(int sock);
+    static bool isConnected(int sock);
+  private:
+    bool closeFd;
+  };
+
+  class UnixListener : public SocketListener {
+  public:
+    UnixListener(const char *listenaddr, int mode,
+		int sock=-1, bool close=true);
+    virtual ~UnixListener();
+
+    virtual void shutdown();
+    virtual Socket* accept();
+
+    int getMyPort();
+
+  private:
+    bool closeFd;
+  };
+
+}
+
+#endif // __NETWORK_UNIX_SOCKET_H__
--- tigervnc-1.1.0.orig/common/rfb/Configuration.cxx	2011-08-09 23:16:44.000000000 +0200
+++ tigervnc-1.1.0/common/rfb/Configuration.cxx	2012-10-06 20:50:22.326954919 +0200
@@ -368,7 +368,7 @@
 IntParameter::setParam(const char* v) {
   if (immutable) return true;
   vlog.debug("set %s(Int) to %s", getName(), v);
-  int i = atoi(v);
+  int i = strtol(v, NULL, 0);
   if (i < minValue || i > maxValue)
     return false;
   value = i;
--- tigervnc-1.1.0.orig/unix/vncviewer/CConn.cxx	2012-10-06 16:35:40.773469213 +0200
+++ tigervnc-1.1.0/unix/vncviewer/CConn.cxx	2012-10-06 20:50:22.327954919 +0200
@@ -36,6 +36,9 @@
 #include <rfb/Password.h>
 #include <rfb/screenTypes.h>
 #include <network/TcpSocket.h>
+#ifndef WIN32
+#include <network/UnixSocket.h>
+#endif
 #include <cassert>
 #include <list>
 #include <string>
@@ -101,6 +104,12 @@
     char* name = sock->getPeerEndpoint();
     vlog.info("Accepted connection from %s", name);
     if (name) free(name);
+#ifndef WIN32
+  } else if (vncServerName && strchr(vncServerName, '/') != NULL) {
+    sock = new network::UnixSocket(vncServerName);
+    serverHost = sock->getPeerAddress();
+    vlog.info("connected to socket %s", serverHost);
+#endif
   } else {
     if (vncServerName) {
       getHostAndPort(vncServerName, &serverHost, &serverPort);
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/vncExtInit.cc	2012-10-06 16:35:40.890469244 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/vncExtInit.cc	2012-10-06 20:50:22.328954919 +0200
@@ -52,6 +52,9 @@
 #undef max
 #undef min
 #include <network/TcpSocket.h>
+#ifndef WIN32
+#include <network/UnixSocket.h>
+#endif
 
 #include "XserverDesktop.h"
 #include "vncHooks.h"
@@ -118,6 +121,10 @@
 rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
                             &rfb::Server::clientWaitTimeMillis);
 rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
+#ifndef WIN32
+rfb::StringParameter rfbpath("rfbpath", "Unix socket to listen for RFB protocol", "");
+rfb::IntParameter rfbmode("rfbmode", "Unix socket access mode",0600);
+#endif
 rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
 rfb::BoolParameter localhostOnly("localhost",
                                  "Only allow connections from localhost",
@@ -217,7 +224,7 @@
     for (int scr = 0; scr < screenInfo.numScreens; scr++) {
 
       if (!desktop[scr]) {
-        network::TcpListener* listener = 0;
+        network::SocketListener* listener = 0;
         network::TcpListener* httpListener = 0;
         if (scr == 0 && vncInetdSock != -1) {
           if (network::TcpSocket::isSocket(vncInetdSock) &&
@@ -226,9 +233,17 @@
             listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
             vlog.info("inetd wait");
           }
+#ifndef WIN32
+	} else if (rfbpath.getValueStr()[0] != '\0') {
+	  const char *path = rfbpath.getValueStr();
+	  int mode = (int)rfbmode;
+	  vlog.info("using Unix domain socket %s (mode %04o)", path, mode);
+	  listener = new network::UnixListener(path, mode);
+#endif
         } else {
           int port = rfbport;
           if (port == 0) port = 5900 + atoi(display);
+	  vlog.info("using TCP socket on port %d", port);
           port += 1000 * scr;
           listener = new network::TcpListener(listenaddr, port, localhostOnly);
           vlog.info("Listening for VNC connections on %s interface(s), port %d",
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/XserverDesktop.cc	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/XserverDesktop.cc	2012-10-06 20:50:22.329954919 +0200
@@ -33,7 +33,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/utsname.h>
-#include <network/TcpSocket.h>
+#include <network/Socket.h>
 #include <rfb/Exception.h>
 #include <rfb/VNCServerST.h>
 #include <rfb/HTTPServer.h>
@@ -141,8 +141,8 @@
 
 
 XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
-                               network::TcpListener* listener_,
-                               network::TcpListener* httpListener_,
+                               network::SocketListener* listener_,
+                               network::SocketListener* httpListener_,
                                const char* name, const rfb::PixelFormat &pf,
                                void* fbptr, int stride)
   : pScreen(pScreen_), deferredUpdateTimer(0), dummyTimer(0),
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/XserverDesktop.h	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/XserverDesktop.h	2012-10-06 20:50:22.329954919 +0200
@@ -45,15 +45,15 @@
   class VNCServerST;
 }
 
-namespace network { class TcpListener; class Socket; }
+namespace network { class SocketListener; class Socket; }
 
 class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
                        public rfb::ColourMap, public rdr::Substitutor,
                        public rfb::VNCServerST::QueryConnectionHandler {
 public:
 
-  XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
-                 network::TcpListener* httpListener_,
+  XserverDesktop(ScreenPtr pScreen, network::SocketListener* listener,
+                 network::SocketListener* httpListener_,
                  const char* name, const rfb::PixelFormat &pf,
                  void* fbptr, int stride);
   virtual ~XserverDesktop();
@@ -126,8 +126,8 @@
   OsTimerPtr deferredUpdateTimer, dummyTimer;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
-  network::TcpListener* listener;
-  network::TcpListener* httpListener;
+  network::SocketListener* listener;
+  network::SocketListener* httpListener;
   ColormapPtr cmap;
   int stride_;
   bool deferredUpdateTimerSet;
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/Xvnc.man	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/Xvnc.man	2012-10-06 20:50:22.330954919 +0200
@@ -92,6 +92,15 @@
 5900 plus the display number.
 
 .TP
+.B \-rfbpath \fIpath\fP
+Specifies the path of a Unix domain socket on which Xvnc listens for
+connections from viewers, instead of listening on a TCP port.
+
+.TP
+.B \-rfbmode \fImode\fP
+Specifies the mode of the Unix domain socket.  The default is 0600.
+
+.TP
 .B \-rfbwait \fItime\fP, \-ClientWaitTimeMillis \fItime\fP
 
 Time in milliseconds to wait for a viewer which is blocking Xvnc.  This is

Reply via email to