aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml22
-rw-r--r--.gitignore3
-rw-r--r--common/network/Socket.h35
-rw-r--r--common/os/os.cxx86
-rw-r--r--common/os/os.h41
-rw-r--r--common/rfb/AccessRights.cxx36
-rw-r--r--common/rfb/AccessRights.h41
-rw-r--r--common/rfb/CMakeLists.txt1
-rw-r--r--common/rfb/CSecurityTLS.cxx27
-rw-r--r--common/rfb/SConnection.cxx18
-rw-r--r--common/rfb/SConnection.h17
-rw-r--r--common/rfb/SSecurity.h2
-rw-r--r--common/rfb/SSecurityRSAAES.cxx6
-rw-r--r--common/rfb/SSecurityRSAAES.h4
-rw-r--r--common/rfb/SSecurityStack.cxx6
-rw-r--r--common/rfb/SSecurityStack.h2
-rw-r--r--common/rfb/SSecurityVeNCrypt.cxx2
-rw-r--r--common/rfb/SSecurityVeNCrypt.h2
-rw-r--r--common/rfb/SSecurityVncAuth.cxx6
-rw-r--r--common/rfb/SSecurityVncAuth.h4
-rw-r--r--common/rfb/VNCSConnectionST.cxx5
-rw-r--r--common/rfb/VNCSConnectionST.h3
-rw-r--r--common/rfb/VNCServer.h39
-rw-r--r--common/rfb/VNCServerST.cxx14
-rw-r--r--common/rfb/VNCServerST.h8
-rw-r--r--common/rfb/obfuscate.cxx4
-rw-r--r--common/rfb/util.cxx4
-rw-r--r--contrib/packages/rpm/el7/SOURCES/10-libvnc.conf2
-rw-r--r--contrib/packages/rpm/el8/SOURCES/10-libvnc.conf2
-rw-r--r--contrib/packages/rpm/el9/SOURCES/10-libvnc.conf2
-rw-r--r--java/.gitignore4
-rw-r--r--java/CMakeLists.txt6
-rw-r--r--java/cmake/SignJar.cmake41
-rw-r--r--java/com/tigervnc/rfb/CSecurityTLS.java9
-rw-r--r--java/com/tigervnc/vncviewer/FileUtils.java52
-rw-r--r--java/com/tigervnc/vncviewer/Parameters.java18
-rw-r--r--java/com/tigervnc/vncviewer/ServerDialog.java6
-rw-r--r--java/com/tigervnc/vncviewer/Viewport.java33
-rw-r--r--tests/.gitignore5
-rw-r--r--tests/perf/encperf.cxx7
-rw-r--r--unix/vncconfig/vncExt.c3
-rw-r--r--unix/vncconfig/vncExt.h4
-rw-r--r--unix/vncconfig/vncconfig.cxx13
-rw-r--r--unix/vncconfig/vncconfig.man7
-rw-r--r--unix/vncpasswd/vncpasswd.cxx14
-rw-r--r--unix/vncpasswd/vncpasswd.man15
-rw-r--r--unix/vncserver/.gitignore5
-rw-r--r--unix/vncserver/HOWTO.md11
-rw-r--r--unix/vncserver/selinux/.gitignore2
-rw-r--r--unix/vncserver/selinux/Makefile5
-rw-r--r--unix/vncserver/selinux/vncsession.fc6
-rw-r--r--unix/vncserver/selinux/vncsession.te23
-rw-r--r--unix/vncserver/tigervnc.pam4
-rw-r--r--unix/vncserver/vncserver-config-defaults2
-rw-r--r--unix/vncserver/vncserver-config-mandatory2
-rwxr-xr-xunix/vncserver/vncserver.in10
-rw-r--r--unix/vncserver/vncsession.c92
-rw-r--r--unix/vncserver/vncsession.man.in50
-rw-r--r--unix/x0vncserver/XDesktop.cxx2
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc8
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h8
-rw-r--r--unix/xserver/hw/vnc/Xvnc.man2
-rw-r--r--unix/xserver/hw/vnc/vncExt.c2
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc8
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h2
-rw-r--r--vncviewer/.gitignore1
-rw-r--r--vncviewer/CConn.cxx2
-rw-r--r--vncviewer/DesktopWindow.cxx12
-rw-r--r--vncviewer/ServerDialog.cxx16
-rw-r--r--vncviewer/parameters.cxx16
-rw-r--r--vncviewer/vncviewer.cxx40
-rw-r--r--vncviewer/vncviewer.man31
-rw-r--r--win/rfb_win32/SocketManager.cxx12
-rw-r--r--win/rfb_win32/SocketManager.h32
-rw-r--r--win/winvnc/ManagedListener.cxx2
-rw-r--r--win/winvnc/ManagedListener.h6
-rw-r--r--win/winvnc/VNCServerWin32.cxx30
77 files changed, 748 insertions, 377 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a34badb7..f41f7791 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
@@ -23,7 +23,7 @@ jobs:
- name: Install
working-directory: build
run: make tarball
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: Linux (Ubuntu)
path: build/tigervnc-*.tar.gz
@@ -35,7 +35,7 @@ jobs:
run:
shell: msys2 {0}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
- name: Install dependencies
run: |
@@ -55,7 +55,7 @@ jobs:
env:
MSYS2_PATH_TYPE: inherit
run: make installer winvnc_installer
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: Windows
path: build/release/tigervnc*.exe
@@ -64,7 +64,7 @@ jobs:
runs-on: macos-latest
timeout-minutes: 20
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install fltk pixman ffmpeg
@@ -77,7 +77,7 @@ jobs:
- name: Install
working-directory: build
run: make dmg
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: macOS
path: build/TigerVNC-*.dmg
@@ -89,9 +89,9 @@ jobs:
matrix:
java: [ '8', '11', '16' ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup java
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
@@ -101,7 +101,7 @@ jobs:
- name: Build
working-directory: java/build
run: make
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: Java (${{ matrix.java }})
path: java/build/VncViewer.jar
@@ -122,12 +122,12 @@ jobs:
env:
DOCKER: ${{ matrix.target }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build image
run: docker build -t tigervnc/$DOCKER .github/containers/$DOCKER
- name: Build packages
run: .github/containers/$DOCKER/build.sh
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: Packages (${{ matrix.target }})
path: .github/containers/${{ matrix.target }}/result
diff --git a/.gitignore b/.gitignore
index 2e864422..85ba95f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@ CMakeCache.txt
Makefile
Makefile.in
config.h
+cmake_install.cmake
+cmake_uninstall.cmake
+install_manifest.txt
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 117851c1..7085d73a 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -111,41 +111,6 @@ namespace network {
SocketException(const char* text, int err_) : rdr::SystemException(text, err_) {}
};
- class SocketServer {
- public:
- virtual ~SocketServer() {}
-
- // addSocket() tells the server to serve the Socket. The caller
- // retains ownership of the Socket - the only way for the server
- // to discard a Socket is by calling shutdown() on it.
- // outgoing is set to true if the socket was created by connecting out
- // to another host, or false if the socket was created by accept()ing
- // an incoming connection.
- virtual void addSocket(network::Socket* sock, bool outgoing=false) = 0;
-
- // removeSocket() tells the server to stop serving the Socket. The
- // caller retains ownership of the Socket - the server must NOT
- // delete the Socket! This call is used mainly to cause per-Socket
- // resources to be freed.
- virtual void removeSocket(network::Socket* sock) = 0;
-
- // getSockets() gets a list of sockets. This can be used to generate an
- // fd_set for calling select().
- virtual void getSockets(std::list<network::Socket*>* sockets) = 0;
-
- // processSocketReadEvent() tells the server there is a Socket read event.
- // The implementation can indicate that the Socket is no longer active
- // by calling shutdown() on it. The caller will then call removeSocket()
- // soon after processSocketEvent returns, to allow any pre-Socket
- // resources to be tidied up.
- virtual void processSocketReadEvent(network::Socket* sock) = 0;
-
- // processSocketReadEvent() tells the server there is a Socket write event.
- // This is only necessary if the Socket has been put in non-blocking
- // mode and needs this callback to flush the buffer.
- virtual void processSocketWriteEvent(network::Socket* sock) = 0;
- };
-
}
#endif // __NETWORK_SOCKET_H__
diff --git a/common/os/os.cxx b/common/os/os.cxx
index 2dfabc46..83995d0d 100644
--- a/common/os/os.cxx
+++ b/common/os/os.cxx
@@ -24,6 +24,9 @@
#include <os/os.h>
#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#ifndef WIN32
#include <pwd.h>
@@ -31,20 +34,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <unistd.h>
#else
#include <windows.h>
#include <wininet.h> /* MinGW needs it */
#include <shlobj.h>
+#define stat _stat
+#define mkdir(path, mode) mkdir(path)
#endif
-static const char* gethomedir(bool userDir)
+static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def)
{
- static char dir[PATH_MAX];
+ static char dir[PATH_MAX], legacy[PATH_MAX];
+ struct stat st;
#ifndef WIN32
- char *homedir;
+ char *homedir, *xdgdir;
uid_t uid;
struct passwd *passwd;
#else
@@ -66,10 +71,17 @@ static const char* gethomedir(bool userDir)
if (userDir)
return homedir;
- snprintf(dir, sizeof(dir), "%s/.vnc", homedir);
+ xdgdir = getenv(xdg_env);
+ if (xdgdir != NULL && xdgdir[0] == '/')
+ snprintf(dir, sizeof(dir), "%s/tigervnc", xdgdir);
+ else
+ snprintf(dir, sizeof(dir), "%s/%s/tigervnc", homedir, xdg_def);
- return dir;
+ snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir);
#else
+ (void) xdg_def;
+ (void) xdg_env;
+
if (userDir)
ret = SHGetSpecialFolderPath(NULL, dir, CSIDL_PROFILE, FALSE);
else
@@ -81,22 +93,70 @@ static const char* gethomedir(bool userDir)
if (userDir)
return dir;
- if (strlen(dir) + strlen("\\vnc") >= sizeof(dir))
+ ret = SHGetSpecialFolderPath(NULL, legacy, CSIDL_APPDATA, FALSE);
+
+ if (ret == FALSE)
return NULL;
- strcat(dir, "\\vnc");
+ if (strlen(dir) + strlen("\\TigerVNC") >= sizeof(dir))
+ return NULL;
+ if (strlen(legacy) + strlen("\\vnc") >= sizeof(legacy))
+ return NULL;
- return dir;
+ strcat(dir, "\\TigerVNC");
+ strcat(legacy, "\\vnc");
#endif
+ return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir;
}
-const char* os::getvnchomedir()
+const char* os::getuserhomedir()
{
- return gethomedir(false);
+ return getvncdir(true, NULL, NULL);
}
-const char* os::getuserhomedir()
+const char* os::getvncconfigdir()
{
- return gethomedir(true);
+ return getvncdir(false, "XDG_CONFIG_HOME", ".config");
}
+const char* os::getvncdatadir()
+{
+ return getvncdir(false, "XDG_DATA_HOME", ".local/share");
+}
+
+const char* os::getvncstatedir()
+{
+ return getvncdir(false, "XDG_STATE_HOME", ".local/state");
+}
+
+int os::mkdir_p(const char *path_, mode_t mode)
+{
+ char *path = strdup(path_);
+ char *p;
+
+#ifdef WIN32
+ (void)mode;
+#endif
+
+ for (p = path + 1; *p; p++) {
+ if (*p == '/') {
+ *p = '\0';
+ if (mkdir(path, mode) == -1) {
+ if (errno != EEXIST) {
+ free(path);
+ return -1;
+ }
+ }
+ *p = '/';
+ }
+ }
+
+ if (mkdir(path, mode) == -1) {
+ free(path);
+ return -1;
+ }
+
+ free(path);
+
+ return 0;
+}
diff --git a/common/os/os.h b/common/os/os.h
index 5f927fef..a3448070 100644
--- a/common/os/os.h
+++ b/common/os/os.h
@@ -20,26 +20,55 @@
#ifndef OS_OS_H
#define OS_OS_H
+#include <sys/stat.h>
+
namespace os {
/*
- * Get VNC home directory ($HOME/.vnc or %APPDATA%/vnc/).
+ * Get user home directory.
* If HOME environment variable is set then it is used.
* Otherwise home directory is obtained via getpwuid function.
*
* Returns NULL on failure.
*/
- const char* getvnchomedir();
+ const char* getuserhomedir();
/*
- * Get user home directory.
- * If HOME environment variable is set then it is used.
- * Otherwise home directory is obtained via getpwuid function.
+ * Get VNC config directory. On Unix-like systems, this is either:
+ * - $XDG_CONFIG_HOME/tigervnc
+ * - $HOME/.config/tigervnc
+ * On Windows, this is simply %APPDATA%/TigerVNC/.
*
* Returns NULL on failure.
*/
- const char* getuserhomedir();
+ const char* getvncconfigdir();
+ /*
+ * Get VNC data directory used for X.509 known hosts.
+ * On Unix-like systems, this is either:
+ * - $XDG_DATA_HOME/tigervnc
+ * - $HOME/.local/share/tigervnc
+ * On Windows, this is simply %APPDATA%/TigerVNC/.
+ *
+ * Returns NULL on failure.
+ */
+ const char* getvncdatadir();
+
+ /*
+ * Get VNC state (logs) directory. On Unix-like systems, this is either:
+ * - $XDG_STATE_HOME/tigervnc
+ * - $HOME/.local/state/tigervnc
+ * On Windows, this is simply %APPDATA%/TigerVNC/.
+ *
+ * Returns NULL on failure.
+ */
+ const char* getvncstatedir();
+
+ /*
+ * Create directory recursively. Useful to create the nested directory
+ * structures needed for the above directories.
+ */
+ int mkdir_p(const char *path, mode_t mode);
}
#endif /* OS_OS_H */
diff --git a/common/rfb/AccessRights.cxx b/common/rfb/AccessRights.cxx
new file mode 100644
index 00000000..65e6ce24
--- /dev/null
+++ b/common/rfb/AccessRights.cxx
@@ -0,0 +1,36 @@
+/* Copyright 2024 TigerVNC Team
+ *
+ * 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.
+ */
+
+#include "AccessRights.h"
+
+namespace rfb
+{
+
+ // AccessRights values
+ const AccessRights AccessNone = 0x0000;
+ const AccessRights AccessView = 0x0001;
+ const AccessRights AccessKeyEvents = 0x0002;
+ const AccessRights AccessPtrEvents = 0x0004;
+ const AccessRights AccessCutText = 0x0008;
+ const AccessRights AccessSetDesktopSize = 0x0010;
+ const AccessRights AccessNonShared = 0x0020;
+ const AccessRights AccessDefault = 0x03ff;
+ const AccessRights AccessNoQuery = 0x0400;
+ const AccessRights AccessFull = 0xffff;
+
+} /* namespace rfb */
diff --git a/common/rfb/AccessRights.h b/common/rfb/AccessRights.h
new file mode 100644
index 00000000..adf4393d
--- /dev/null
+++ b/common/rfb/AccessRights.h
@@ -0,0 +1,41 @@
+/* Copyright 2024 TigerVNC Team
+ *
+ * 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.
+ */
+
+#ifndef COMMON_RFB_ACCESSRIGHTS_H_
+#define COMMON_RFB_ACCESSRIGHTS_H_
+
+#include <stdint.h>
+
+namespace rfb
+{
+
+ typedef uint16_t AccessRights;
+ extern const AccessRights AccessNone; // No rights at all
+ extern const AccessRights AccessView; // View display contents
+ extern const AccessRights AccessKeyEvents; // Send key events
+ extern const AccessRights AccessPtrEvents; // Send pointer events
+ extern const AccessRights AccessCutText; // Send/receive clipboard events
+ extern const AccessRights AccessSetDesktopSize; // Change desktop size
+ extern const AccessRights AccessNonShared; // Exclusive access to the server
+ extern const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
+ extern const AccessRights AccessNoQuery; // Connect without local user accepting
+ extern const AccessRights AccessFull; // All of the available AND FUTURE rights
+
+} /* namespace rfb */
+
+#endif /* COMMON_RFB_ACCESSRIGHTS_H_ */
diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt
index 2cae2356..360434a9 100644
--- a/common/rfb/CMakeLists.txt
+++ b/common/rfb/CMakeLists.txt
@@ -1,4 +1,5 @@
add_library(rfb STATIC
+ AccessRights.cxx
Blacklist.cxx
Congestion.cxx
CConnection.cxx
diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index 90540959..11e6dfe3 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -58,28 +58,27 @@
using namespace rfb;
-static const char* homedirfn(const char* fn);
+static const char* configdirfn(const char* fn);
StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate",
- homedirfn("x509_ca.pem"),
+ configdirfn("x509_ca.pem"),
ConfViewer);
StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file",
- homedirfn("x509_crl.pem"),
+ configdirfn("x509_crl.pem"),
ConfViewer);
static LogWriter vlog("TLS");
-static const char* homedirfn(const char* fn)
+static const char* configdirfn(const char* fn)
{
static char full_path[PATH_MAX];
- const char* homedir;
+ const char* configdir;
- homedir = os::getvnchomedir();
- if (homedir == NULL)
+ configdir = os::getvncconfigdir();
+ if (configdir == NULL)
return "";
- snprintf(full_path, sizeof(full_path), "%s/%s", homedir, fn);
-
+ snprintf(full_path, sizeof(full_path), "%s/%s", configdir, fn);
return full_path;
}
@@ -308,7 +307,7 @@ void CSecurityTLS::checkSession()
int err;
bool hostname_match;
- const char *homeDir;
+ const char *hostsDir;
gnutls_datum_t info;
size_t len;
@@ -385,14 +384,14 @@ void CSecurityTLS::checkSession()
/* Certificate has some user overridable problems, so TOFU time */
- homeDir = os::getvnchomedir();
- if (homeDir == NULL) {
- throw AuthFailureException("Could not obtain VNC home directory "
+ hostsDir = os::getvncstatedir();
+ if (hostsDir == NULL) {
+ throw AuthFailureException("Could not obtain VNC state directory "
"path for known hosts storage");
}
std::string dbPath;
- dbPath = (std::string)homeDir + "/x509_known_hosts";
+ dbPath = (std::string)hostsDir + "/x509_known_hosts";
err = gnutls_verify_stored_pubkey(dbPath.c_str(), NULL,
client->getServerName(), NULL,
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index 402b0c04..12ba0f1a 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -43,24 +43,12 @@ using namespace rfb;
static LogWriter vlog("SConnection");
-// AccessRights values
-const SConnection::AccessRights SConnection::AccessView = 0x0001;
-const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
-const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
-const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
-const SConnection::AccessRights SConnection::AccessSetDesktopSize = 0x0010;
-const SConnection::AccessRights SConnection::AccessNonShared = 0x0020;
-const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
-const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
-const SConnection::AccessRights SConnection::AccessFull = 0xffff;
-
-
-SConnection::SConnection()
+SConnection::SConnection(AccessRights accessRights)
: readyForSetColourMapEntries(false),
is(0), os(0), reader_(0), writer_(0), ssecurity(0),
authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
- accessRights(0x0000), hasRemoteClipboard(false),
+ accessRights(accessRights), hasRemoteClipboard(false),
hasLocalClipboard(false),
unsolicitedClipboardAttempt(false)
{
@@ -254,7 +242,7 @@ bool SConnection::processSecurityMsg()
}
state_ = RFBSTATE_QUERYING;
- setAccessRights(ssecurity->getAccessRights());
+ setAccessRights(accessRights & ssecurity->getAccessRights());
queryConnection(ssecurity->getUserName());
// If the connection got approved right away then we can continue
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 0bd6afdb..5bc61677 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -29,6 +29,7 @@
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
+#include <rfb/AccessRights.h>
#include <rfb/SMsgHandler.h>
#include <rfb/SecurityServer.h>
#include <rfb/Timer.h>
@@ -42,7 +43,7 @@ namespace rfb {
class SConnection : public SMsgHandler {
public:
- SConnection();
+ SConnection(AccessRights accessRights);
virtual ~SConnection();
// Methods to initialise the connection
@@ -175,20 +176,12 @@ namespace rfb {
// clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data);
+ // getAccessRights() returns the access rights of a SConnection to the server.
+ AccessRights getAccessRights() { return accessRights; }
+
// setAccessRights() allows a security package to limit the access rights
// of a SConnection to the server. How the access rights are treated
// is up to the derived class.
-
- typedef uint16_t AccessRights;
- static const AccessRights AccessView; // View display contents
- static const AccessRights AccessKeyEvents; // Send key events
- static const AccessRights AccessPtrEvents; // Send pointer events
- static const AccessRights AccessCutText; // Send/receive clipboard events
- static const AccessRights AccessSetDesktopSize; // Change desktop size
- static const AccessRights AccessNonShared; // Exclusive access to the server
- static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
- static const AccessRights AccessNoQuery; // Connect without local user accepting
- static const AccessRights AccessFull; // All of the available AND FUTURE rights
virtual void setAccessRights(AccessRights ar);
virtual bool accessCheck(AccessRights ar) const;
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
index fbc3de6f..8e296c5a 100644
--- a/common/rfb/SSecurity.h
+++ b/common/rfb/SSecurity.h
@@ -62,7 +62,7 @@ namespace rfb {
// for this security type.
virtual const char* getUserName() const = 0;
- virtual SConnection::AccessRights getAccessRights() const { return SConnection::AccessDefault; }
+ virtual AccessRights getAccessRights() const { return AccessDefault; }
protected:
SConnection* sc;
diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx
index 2a8dfa3e..cea62644 100644
--- a/common/rfb/SSecurityRSAAES.cxx
+++ b/common/rfb/SSecurityRSAAES.cxx
@@ -76,7 +76,7 @@ SSecurityRSAAES::SSecurityRSAAES(SConnection* sc, uint32_t _secType,
keySize(_keySize), isAllEncrypted(_isAllEncrypted), secType(_secType),
serverKey(), clientKey(),
serverKeyN(NULL), serverKeyE(NULL), clientKeyN(NULL), clientKeyE(NULL),
- accessRights(SConnection::AccessDefault),
+ accessRights(AccessDefault),
rais(NULL), raos(NULL), rawis(NULL), rawos(NULL)
{
assert(keySize == 128 || keySize == 256);
@@ -578,12 +578,12 @@ void SSecurityRSAAES::verifyPass()
throw AuthFailureException("No password configured for VNC Auth");
if (password == passwd) {
- accessRights = SConnection::AccessDefault;
+ accessRights = AccessDefault;
return;
}
if (!passwdReadOnly.empty() && password == passwdReadOnly) {
- accessRights = SConnection::AccessView;
+ accessRights = AccessView;
return;
}
diff --git a/common/rfb/SSecurityRSAAES.h b/common/rfb/SSecurityRSAAES.h
index eaeb13a1..0c4fc852 100644
--- a/common/rfb/SSecurityRSAAES.h
+++ b/common/rfb/SSecurityRSAAES.h
@@ -39,7 +39,7 @@ namespace rfb {
virtual bool processMsg();
virtual const char* getUserName() const;
virtual int getType() const { return secType; }
- virtual SConnection::AccessRights getAccessRights() const
+ virtual AccessRights getAccessRights() const
{
return accessRights;
}
@@ -82,7 +82,7 @@ namespace rfb {
char username[256];
char password[256];
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
rdr::InStream* rais;
rdr::OutStream* raos;
diff --git a/common/rfb/SSecurityStack.cxx b/common/rfb/SSecurityStack.cxx
index 8b1c2a47..9c0321d4 100644
--- a/common/rfb/SSecurityStack.cxx
+++ b/common/rfb/SSecurityStack.cxx
@@ -71,14 +71,14 @@ const char* SSecurityStack::getUserName() const
return c;
}
-SConnection::AccessRights SSecurityStack::getAccessRights() const
+AccessRights SSecurityStack::getAccessRights() const
{
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
if (!state0 && !state1)
return SSecurity::getAccessRights();
- accessRights = SConnection::AccessFull;
+ accessRights = AccessFull;
if (state0)
accessRights &= state0->getAccessRights();
diff --git a/common/rfb/SSecurityStack.h b/common/rfb/SSecurityStack.h
index 8b412bdf..cf7b10d0 100644
--- a/common/rfb/SSecurityStack.h
+++ b/common/rfb/SSecurityStack.h
@@ -32,7 +32,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const { return type; };
virtual const char* getUserName() const;
- virtual SConnection::AccessRights getAccessRights() const;
+ virtual AccessRights getAccessRights() const;
protected:
short state;
SSecurity* state0;
diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx
index c126d82f..2813f299 100644
--- a/common/rfb/SSecurityVeNCrypt.cxx
+++ b/common/rfb/SSecurityVeNCrypt.cxx
@@ -180,7 +180,7 @@ const char* SSecurityVeNCrypt::getUserName() const
return ssecurity->getUserName();
}
-SConnection::AccessRights SSecurityVeNCrypt::getAccessRights() const
+AccessRights SSecurityVeNCrypt::getAccessRights() const
{
if (ssecurity == NULL)
return SSecurity::getAccessRights();
diff --git a/common/rfb/SSecurityVeNCrypt.h b/common/rfb/SSecurityVeNCrypt.h
index 86cf420a..91713f89 100644
--- a/common/rfb/SSecurityVeNCrypt.h
+++ b/common/rfb/SSecurityVeNCrypt.h
@@ -37,7 +37,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const { return chosenType; }
virtual const char* getUserName() const;
- virtual SConnection::AccessRights getAccessRights() const;
+ virtual AccessRights getAccessRights() const;
protected:
SSecurity *ssecurity;
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
index cbd0ccd2..c1ef1f1c 100644
--- a/common/rfb/SSecurityVncAuth.cxx
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -54,7 +54,7 @@ VncAuthPasswdParameter SSecurityVncAuth::vncAuthPasswd
SSecurityVncAuth::SSecurityVncAuth(SConnection* sc)
: SSecurity(sc), sentChallenge(false),
- pg(&vncAuthPasswd), accessRights(0)
+ pg(&vncAuthPasswd), accessRights(AccessNone)
{
}
@@ -103,13 +103,13 @@ bool SSecurityVncAuth::processMsg()
throw AuthFailureException("No password configured for VNC Auth");
if (verifyResponse(passwd.c_str())) {
- accessRights = SConnection::AccessDefault;
+ accessRights = AccessDefault;
return true;
}
if (!passwdReadOnly.empty() &&
verifyResponse(passwdReadOnly.c_str())) {
- accessRights = SConnection::AccessView;
+ accessRights = AccessView;
return true;
}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
index 2bd27791..7f27b02b 100644
--- a/common/rfb/SSecurityVncAuth.h
+++ b/common/rfb/SSecurityVncAuth.h
@@ -55,7 +55,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const {return secTypeVncAuth;}
virtual const char* getUserName() const {return 0;}
- virtual SConnection::AccessRights getAccessRights() const { return accessRights; }
+ virtual AccessRights getAccessRights() const { return accessRights; }
static StringParameter vncAuthPasswdFile;
static VncAuthPasswdParameter vncAuthPasswd;
private:
@@ -65,7 +65,7 @@ namespace rfb {
uint8_t response[vncAuthChallengeSize];
bool sentChallenge;
VncAuthPasswdGetter* pg;
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
};
}
#endif
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index ffbf8be7..306bba1d 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -51,8 +51,9 @@ static LogWriter vlog("VNCSConnST");
static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
- bool reverse)
- : sock(s), reverseConnection(reverse),
+ bool reverse, AccessRights ar)
+ : SConnection(ar),
+ sock(s), reverseConnection(reverse),
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 85bfd38f..3a9ec242 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -40,7 +40,8 @@ namespace rfb {
class VNCSConnectionST : private SConnection,
public Timer::Callback {
public:
- VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
+ VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse,
+ AccessRights ar);
virtual ~VNCSConnectionST();
// SConnection methods
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index b49dbfe3..3ac9fb94 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -23,17 +23,48 @@
#ifndef __RFB_VNCSERVER_H__
#define __RFB_VNCSERVER_H__
-#include <network/Socket.h>
-
#include <rfb/UpdateTracker.h>
#include <rfb/SSecurity.h>
#include <rfb/ScreenSet.h>
+namespace network { class Socket; }
+
namespace rfb {
- class VNCServer : public UpdateTracker,
- public network::SocketServer {
+ class VNCServer : public UpdateTracker {
public:
+ // addSocket() tells the server to serve the Socket. The caller
+ // retains ownership of the Socket - the only way for the server
+ // to discard a Socket is by calling shutdown() on it.
+ // outgoing is set to true if the socket was created by connecting out
+ // to another host, or false if the socket was created by accept()ing
+ // an incoming connection.
+ // accessRights allows to set the access rights to the server.
+ virtual void addSocket(network::Socket* sock, bool outgoing=false,
+ AccessRights accessRights = AccessDefault) = 0;
+
+ // removeSocket() tells the server to stop serving the Socket. The
+ // caller retains ownership of the Socket - the server must NOT
+ // delete the Socket! This call is used mainly to cause per-Socket
+ // resources to be freed.
+ virtual void removeSocket(network::Socket* sock) = 0;
+
+ // getSockets() gets a list of sockets. This can be used to generate an
+ // fd_set for calling select().
+ virtual void getSockets(std::list<network::Socket*>* sockets) = 0;
+
+ // processSocketReadEvent() tells the server there is a Socket read event.
+ // The implementation can indicate that the Socket is no longer active
+ // by calling shutdown() on it. The caller will then call removeSocket()
+ // soon after processSocketEvent returns, to allow any pre-Socket
+ // resources to be tidied up.
+ virtual void processSocketReadEvent(network::Socket* sock) = 0;
+
+ // processSocketReadEvent() tells the server there is a Socket write event.
+ // This is only necessary if the Socket has been put in non-blocking
+ // mode and needs this callback to flush the buffer.
+ virtual void processSocketWriteEvent(network::Socket* sock) = 0;
+
// blockUpdates()/unblockUpdates() tells the server that the pixel buffer
// is currently in flux and may not be accessed. The attributes of the
// pixel buffer may still be accessed, but not the frame buffer itself.
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 72cf942d..b9579f12 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -55,6 +55,8 @@
#include <assert.h>
#include <stdlib.h>
+#include <network/Socket.h>
+
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/Exception.h>
#include <rfb/KeyRemapper.h>
@@ -130,9 +132,9 @@ VNCServerST::~VNCServerST()
}
-// SocketServer methods
+// VNCServer methods
-void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
+void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights accessRights)
{
// - Check the connection isn't black-marked
// *** do this in getSecurity instead?
@@ -163,7 +165,7 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime));
disconnectTimer.stop();
- VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+ VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights);
clients.push_front(client);
client->init();
}
@@ -235,8 +237,6 @@ void VNCServerST::processSocketWriteEvent(network::Socket* sock)
throw rdr::Exception("invalid Socket in VNCServerST");
}
-// VNCServer methods
-
void VNCServerST::blockUpdates()
{
blockCounter++;
@@ -702,7 +702,7 @@ void VNCServerST::queryConnection(VNCSConnectionST* client,
}
// - Does the client have the right to bypass the query?
- if (client->accessCheck(SConnection::AccessNoQuery))
+ if (client->accessCheck(AccessNoQuery))
{
approveConnection(client->getSock(), true, NULL);
return;
@@ -715,7 +715,7 @@ void VNCServerST::clientReady(VNCSConnectionST* client, bool shared)
{
if (!shared) {
if (rfb::Server::disconnectClients &&
- client->accessCheck(SConnection::AccessNonShared)) {
+ client->accessCheck(AccessNonShared)) {
// - Close all the other connected clients
slog.debug("non-shared connection - closing clients");
closeClients("Non-shared connection requested", client->getSock());
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 3436d333..90c8d753 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -51,12 +51,13 @@ namespace rfb {
virtual ~VNCServerST();
- // Methods overridden from SocketServer
+ // Methods overridden from VNCServer
// addSocket
// Causes the server to allocate an RFB-protocol management
// structure for the socket & initialise it.
- virtual void addSocket(network::Socket* sock, bool outgoing=false);
+ virtual void addSocket(network::Socket* sock, bool outgoing=false,
+ AccessRights ar=AccessDefault);
// removeSocket
// Clean up any resources associated with the Socket
@@ -76,9 +77,6 @@ namespace rfb {
// Flush pending data from the Socket on to the network.
virtual void processSocketWriteEvent(network::Socket* sock);
-
- // Methods overridden from VNCServer
-
virtual void blockUpdates();
virtual void unblockUpdates();
virtual uint64_t getMsc();
diff --git a/common/rfb/obfuscate.cxx b/common/rfb/obfuscate.cxx
index 1f785893..d40e25c3 100644
--- a/common/rfb/obfuscate.cxx
+++ b/common/rfb/obfuscate.cxx
@@ -56,11 +56,11 @@ std::string rfb::deobfuscate(const uint8_t *data, size_t len)
{
char buf[9];
- assert(data != NULL);
-
if (len != 8)
throw rdr::Exception("bad obfuscated password length");
+ assert(data != NULL);
+
deskey(d3desObfuscationKey, DE1);
des((uint8_t*)data, (uint8_t*)buf);
buf[8] = 0;
diff --git a/common/rfb/util.cxx b/common/rfb/util.cxx
index d1a8cc33..48f59846 100644
--- a/common/rfb/util.cxx
+++ b/common/rfb/util.cxx
@@ -126,8 +126,8 @@ namespace rfb {
bool hexToBin(const char* in, size_t inlen,
uint8_t* out, size_t outlen) {
- assert(in);
- assert(out);
+ assert(in || inlen == 0);
+ assert(out || outlen == 0);
if (inlen & 1)
return false;
diff --git a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
index a053a7d8..9a69fc7d 100644
--- a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
+++ b/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
@@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
-# Option "PasswordFile" "/root/.vnc/passwd"
+# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
diff --git a/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf
index a053a7d8..9a69fc7d 100644
--- a/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf
+++ b/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf
@@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
-# Option "PasswordFile" "/root/.vnc/passwd"
+# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
diff --git a/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf
index a053a7d8..9a69fc7d 100644
--- a/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf
+++ b/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf
@@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
-# Option "PasswordFile" "/root/.vnc/passwd"
+# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
diff --git a/java/.gitignore b/java/.gitignore
new file mode 100644
index 00000000..a99543fd
--- /dev/null
+++ b/java/.gitignore
@@ -0,0 +1,4 @@
+*.class
+*.jar
+.idea/
+timestamp
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 7627a2c5..2fd348f7 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -20,7 +20,10 @@ set(JAVA_KEYSTORE_TYPE "jks" CACHE STRING "Type of keystore (Default: \"jks\")")
set(JAVA_KEY_ALIAS NOTFOUND CACHE STRING "Alias for the keystore entry used to generate the signature")
set(JAVA_STOREPASS NOTFOUND CACHE STRING "Password required to access the keystore")
set(JAVA_KEYPASS NOTFOUND CACHE STRING "Password used to protect the private key of the specified keystore entry")
+set(JAVA_PKCS11_PROVIDER_CLASS "sun.security.pkcs11.SunPKCS11" CACHE STRING "PKCS11 SecurityProvider class name")
+set(JAVA_PKCS11_PROVIDER_ARG NOTFOUND CACHE STRING "Path to the PKCS11 security provider class config file")
set(JAVA_TSA_URL NOTFOUND CACHE STRING "URL of Time Stamping Authority (TSA)")
+set(JAVA_CERT_CHAIN NOTFOUND CACHE STRING "Path to CA certificate chain file")
if(NOT BUILD)
STRING(TIMESTAMP BUILD "%Y%m%d" UTC)
@@ -166,9 +169,12 @@ add_custom_command(OUTPUT VncViewer.jar
-DJAVA_KEYSTORE=${JAVA_KEYSTORE}
-DJAVA_KEYSTORE_TYPE=${JAVA_KEYSTORE_TYPE}
-DJAVA_STOREPASS=${JAVA_STOREPASS}
+ -DJAVA_PKCS11_PROVIDER_CLASS=${JAVA_PKCS11_PROVIDER_CLASS}
+ -DJAVA_PKCS11_PROVIDER_ARG=${JAVA_PKCS11_PROVIDER_ARG}
-DJAVA_KEYPASS=${JAVA_KEYPASS}
-DJAVA_KEY_ALIAS=${JAVA_KEY_ALIAS}
-DJAVA_TSA_URL=${JAVA_TSA_URL}
+ -DJAVA_CERT_CHAIN=${JAVA_CERT_CHAIN}
-P ${SRCDIR}/cmake/SignJar.cmake)
add_custom_target(java ALL DEPENDS VncViewer.jar)
diff --git a/java/cmake/SignJar.cmake b/java/cmake/SignJar.cmake
index 067116d4..cfca1ba2 100644
--- a/java/cmake/SignJar.cmake
+++ b/java/cmake/SignJar.cmake
@@ -10,8 +10,20 @@ set(KEYTOOL "${Java_PATH}/keytool")
set(JARSIGNER "${Java_PATH}/jarsigner")
if(JAVA_KEYSTORE)
- if((NOT JAVA_STOREPASS) OR (NOT JAVA_KEYPASS) OR (NOT JAVA_KEY_ALIAS))
- message(FATAL_ERROR "When JAVA_KEYSTORE is specified, JAVA_KEY_ALIAS, JAVA_STOREPASS, and JAVA_KEYPASS must also be specified:\n${ERROR}")
+ if((NOT JAVA_KEYSTORE_TYPE))
+ message(FATAL_ERROR "When JAVA_KEYSTORE is specified, JAVA_KEYSTORE_TYPE must also be specified:\n${ERROR}")
+ endif()
+ string(TOUPPER "${JAVA_KEYSTORE_TYPE}" JAVA_KEYSTORE_TYPE_STRING)
+ if(${JAVA_KEYSTORE_TYPE_STRING} MATCHES "PKCS11")
+ if((NOT JAVA_PKCS11_PROVIDER_ARG) OR (NOT JAVA_STOREPASS) OR (NOT JAVA_KEY_ALIAS))
+ message(FATAL_ERROR "When JAVA_KEYSTORE_TYPE is PKCS11, JAVA_STOREPASS, JAVA_PKCS11_PROVIDER_ARG, and JAVA_KEY_ALIAS must also be specified:\n${ERROR}")
+ endif()
+ elseif((${JAVA_KEYSTORE_TYPE_STRING} MATCHES "JKS") OR (${JAVA_KEYSTORE_TYPE_STRING} MATCHES "PKCS12"))
+ if((NOT JAVA_STOREPASS) OR (NOT JAVA_KEYPASS) OR (NOT JAVA_KEY_ALIAS))
+ message(FATAL_ERROR "When JAVA_KEYSTORE_TYPE is JKS or PKCS12, JAVA_STOREPASS, JAVA_KEYPASS, and JAVA_KEY_ALIAS must also be specified:\n${ERROR}")
+ endif()
+ else()
+ message(FATAL_ERROR "Unsupported keystore type:\n${ERROR}")
endif()
else()
message(STATUS "Generating self-signed certificate")
@@ -44,14 +56,23 @@ else()
set(ARGS ${ARGS} -storepass ${JAVA_STOREPASS})
endif()
-if(${JAVA_KEYPASS} MATCHES "^:env")
- string(REGEX REPLACE "^:env[\t ]+(.*)$" "\\1" JAVA_KEYPASS "${JAVA_KEYPASS}")
- set(ARGS ${ARGS} -keypass:env ${JAVA_KEYPASS})
-elseif("${JAVA_KEYPASS}" MATCHES "^:file")
- string(REGEX REPLACE "^:file[\t ]+(.*)$" "\\1" JAVA_KEYPASS "${JAVA_KEYPASS}")
- set(ARGS ${ARGS} -keypass:file ${JAVA_KEYPASS})
-else()
- set(ARGS ${ARGS} -keypass ${JAVA_KEYPASS})
+if(${JAVA_KEYSTORE_TYPE_STRING} MATCHES "PKCS11")
+ set(ARGS ${ARGS} -providerClass ${JAVA_PKCS11_PROVIDER_CLASS})
+ set(ARGS ${ARGS} -providerArg ${JAVA_PKCS11_PROVIDER_ARG})
+elseif((${JAVA_KEYSTORE_TYPE_STRING} MATCHES "JKS") OR (${JAVA_KEYSTORE_TYPE_STRING} MATCHES "PKCS12"))
+ if(${JAVA_KEYPASS} MATCHES "^:env")
+ string(REGEX REPLACE "^:env[\t ]+(.*)$" "\\1" JAVA_KEYPASS "${JAVA_KEYPASS}")
+ set(ARGS ${ARGS} -keypass:env ${JAVA_KEYPASS})
+ elseif("${JAVA_KEYPASS}" MATCHES "^:file")
+ string(REGEX REPLACE "^:file[\t ]+(.*)$" "\\1" JAVA_KEYPASS "${JAVA_KEYPASS}")
+ set(ARGS ${ARGS} -keypass:file ${JAVA_KEYPASS})
+ else()
+ set(ARGS ${ARGS} -keypass ${JAVA_KEYPASS})
+ endif()
+endif()
+
+if(JAVA_CERT_CHAIN)
+ set(ARGS ${ARGS} -certchain ${JAVA_CERT_CHAIN})
endif()
if(JAVA_TSA_URL)
diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java
index 14a5eb66..39d1f541 100644
--- a/java/com/tigervnc/rfb/CSecurityTLS.java
+++ b/java/com/tigervnc/rfb/CSecurityTLS.java
@@ -89,13 +89,13 @@ public class CSecurityTLS extends CSecurity {
public static String getDefaultCA() {
if (UserPreferences.get("viewer", "x509ca") != null)
return UserPreferences.get("viewer", "x509ca");
- return FileUtils.getVncHomeDir()+"x509_ca.pem";
+ return FileUtils.getVncConfigDir()+"x509_ca.pem";
}
public static String getDefaultCRL() {
if (UserPreferences.get("viewer", "x509crl") != null)
return UserPreferences.get("viewer", "x509crl");
- return FileUtils.getVncHomeDir()+"x509_crl.pem";
+ return FileUtils.getVncConfigDir()+"x509_crl.pem";
}
public static void setDefaults()
@@ -277,12 +277,12 @@ public class CSecurityTLS extends CSecurity {
"do you want to continue?"))
throw new AuthFailureException("server certificate has expired");
}
- File vncDir = new File(FileUtils.getVncHomeDir());
+ File vncDir = new File(FileUtils.getVncStateDir());
if (!vncDir.exists()) {
try {
vncDir.mkdir();
} catch(SecurityException e) {
- throw new AuthFailureException("Could not obtain VNC home directory "+
+ throw new AuthFailureException("Could not obtain VNC state directory "+
"path for known hosts storage");
}
}
@@ -356,7 +356,6 @@ public class CSecurityTLS extends CSecurity {
private void store_pubkey(File dbPath, String serverName, String pk)
{
ArrayList<String> lines = new ArrayList<String>();
- File vncDir = new File(FileUtils.getVncHomeDir());
try {
if (dbPath.exists()) {
FileReader db = new FileReader(dbPath);
diff --git a/java/com/tigervnc/vncviewer/FileUtils.java b/java/com/tigervnc/vncviewer/FileUtils.java
index af5da3c2..6b82d3e2 100644
--- a/java/com/tigervnc/vncviewer/FileUtils.java
+++ b/java/com/tigervnc/vncviewer/FileUtils.java
@@ -22,9 +22,11 @@ import javax.swing.filechooser.FileSystemView;
import com.tigervnc.rfb.LogWriter;
+import java.io.File;
+
public class FileUtils {
- public static final String getHomeDir() {
+ public static String getHomeDir() {
String homeDir = null;
try {
String os = System.getProperty("os.name");
@@ -56,21 +58,51 @@ public class FileUtils {
vlog.error("Cannot access os.name system property:"+e.getMessage());
}
- String separator = null;
- try {
- separator = Character.toString(java.io.File.separatorChar);
- } catch(java.security.AccessControlException e) {
- vlog.error("Cannot access file.separator system property:"+e.getMessage());
+ return homeDir + getFileSeparator();
+ }
+
+ public static String getVncDir(String xdgEnv, String xdgDefault) {
+ File legacyDir = new File(getHomeDir() + ".vnc" + getFileSeparator());
+ String os = System.getProperty("os.name");
+
+ if (os.startsWith("Windows")) {
+ File newDir = new File(System.getenv("APPDATA") + getFileSeparator() + "TigerVNC" + getFileSeparator());
+ if (!newDir.exists()) {
+ newDir.mkdirs();
+ }
+ File[] existingFiles = legacyDir.listFiles();
+ if (existingFiles != null) {
+ for (File file : existingFiles) {
+ file.renameTo(new File(newDir.getPath() + file.getName()));
+ }
+ legacyDir.delete();
+ }
+ return newDir.getPath();
+ } else {
+ if (legacyDir.exists()) {
+ vlog.info("WARNING: ~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to.");
+ return legacyDir.getPath();
+ }
+ String xdgBaseDir = System.getenv(xdgEnv);
+ return (xdgBaseDir != null && xdgBaseDir.startsWith("/"))
+ ? xdgBaseDir + getFileSeparator() + "tigervnc" + getFileSeparator()
+ : getHomeDir() + xdgDefault + getFileSeparator() + "tigervnc" + getFileSeparator();
}
+ }
- return homeDir + getFileSeparator();
+ public static String getVncConfigDir() {
+ return getVncDir("XDG_CONFIG_HOME", ".config");
+ }
+
+ public static String getVncDataDir() {
+ return getVncDir("XDG_DATA_HOME", ".local" + getFileSeparator() + "share");
}
- public static final String getVncHomeDir() {
- return getHomeDir()+".vnc"+getFileSeparator();
+ public static String getVncStateDir() {
+ return getVncDir("XDG_STATE_HOME", ".local" + getFileSeparator() + "state");
}
- public static final String getFileSeparator() {
+ public static String getFileSeparator() {
String separator = null;
try {
separator = Character.toString(java.io.File.separatorChar);
diff --git a/java/com/tigervnc/vncviewer/Parameters.java b/java/com/tigervnc/vncviewer/Parameters.java
index f08202c0..8c8465cb 100644
--- a/java/com/tigervnc/vncviewer/Parameters.java
+++ b/java/com/tigervnc/vncviewer/Parameters.java
@@ -325,13 +325,6 @@ public class Parameters {
if (filename == null || filename.isEmpty()) {
saveToReg(servername);
return;
- /*
- String homeDir = FileUtils.getVncHomeDir();
- if (homeDir == null)
- throw new Exception("Failed to read configuration file, "+
- "can't obtain home directory path.");
- filepath = homeDir.concat("default.tigervnc");
- */
} else {
filepath = filename;
}
@@ -385,16 +378,7 @@ public class Parameters {
String filepath;
if (filename == null) {
-
- return loadFromReg();
-
- /*
- String homeDir = FileUtils.getVncHomeDir();
- if (homeDir == null)
- throw new Exception("Failed to read configuration file, "+
- "can't obtain home directory path.");
- filepath = homeDir.concat("default.tigervnc");
- */
+ return loadFromReg();
} else {
filepath = filename;
}
diff --git a/java/com/tigervnc/vncviewer/ServerDialog.java b/java/com/tigervnc/vncviewer/ServerDialog.java
index aeee0b21..5f75fd3d 100644
--- a/java/com/tigervnc/vncviewer/ServerDialog.java
+++ b/java/com/tigervnc/vncviewer/ServerDialog.java
@@ -235,7 +235,7 @@ class ServerDialog extends Dialog implements Runnable {
private void handleLoad() {
String title = "Select a TigerVNC configuration file";
- File dflt = new File(FileUtils.getVncHomeDir().concat("default.tigervnc"));
+ File dflt = new File(FileUtils.getVncConfigDir().concat("default.tigervnc"));
FileNameExtensionFilter filter =
new FileNameExtensionFilter("TigerVNC configuration (*.tigervnc)", "tigervnc");
File f = showChooser(title, dflt, filter);
@@ -245,9 +245,9 @@ class ServerDialog extends Dialog implements Runnable {
private void handleSaveAs() {
String title = "Save the TigerVNC configuration to file";
- File dflt = new File(FileUtils.getVncHomeDir().concat("default.tigervnc"));
+ File dflt = new File(FileUtils.getVncConfigDir().concat("default.tigervnc"));
if (!dflt.exists() || !dflt.isFile())
- dflt = new File(FileUtils.getVncHomeDir());
+ dflt = new File(FileUtils.getVncConfigDir());
FileNameExtensionFilter filter =
new FileNameExtensionFilter("TigerVNC configuration (*.tigervnc)", "tigervnc");
File f = showChooser(title, dflt, filter);
diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java
index 2e5e42d6..e12ef2a6 100644
--- a/java/com/tigervnc/vncviewer/Viewport.java
+++ b/java/com/tigervnc/vncviewer/Viewport.java
@@ -149,11 +149,11 @@ class Viewport extends JPanel implements ActionListener {
}
static final int[] dotcursor_xpm = {
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
- 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
- 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
- 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0x00000000,
+ 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0x00000000,
+ 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
public void setCursor(int width, int height, Point hotspot,
@@ -188,23 +188,20 @@ class Viewport extends JPanel implements ActionListener {
}
}
- int cw = (int)Math.floor((float)cursor.getWidth() * scaleRatioX);
- int ch = (int)Math.floor((float)cursor.getHeight() * scaleRatioY);
-
- int x = (int)Math.floor((float)cursorHotspot.x * scaleRatioX);
- int y = (int)Math.floor((float)cursorHotspot.y * scaleRatioY);
-
+ int cw = (int) Math.floor((float) cursor.getWidth() * scaleRatioX);
+ int ch = (int) Math.floor((float) cursor.getHeight() * scaleRatioY);
+ int x = cursorHotspot.x;
+ int y = cursorHotspot.y;
Dimension cs = tk.getBestCursorSize(cw, ch);
- if (cs.width != cw && cs.height != ch) {
- cw = Math.min(cw, cs.width);
- ch = Math.min(ch, cs.height);
- x = (int)Math.min(x, Math.max(cs.width - 1, 0));
- y = (int)Math.min(y, Math.max(cs.height - 1, 0));
- BufferedImage tmp =
- new BufferedImage(cs.width, cs.height, BufferedImage.TYPE_INT_ARGB_PRE);
+ if (cs.width != cursor.getWidth() || cs.height != cursor.getHeight()) {
+ cw = VncViewer.os.startsWith("windows") ? Math.min(cw, cs.width) : cs.width;
+ ch = VncViewer.os.startsWith("windows") ? Math.min(ch, cs.height) : cs.height;
+ BufferedImage tmp = new BufferedImage(cs.width, cs.height, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g2 = tmp.createGraphics();
g2.drawImage(cursor, 0, 0, cw, ch, 0, 0, width, height, null);
g2.dispose();
+ x = (int) Math.min(Math.floor((float) x * (float) cw / (float) width), cw - 1);
+ y = (int) Math.min(Math.floor((float) y * (float) ch / (float) height), ch - 1);
cursor = tmp;
}
diff --git a/tests/.gitignore b/tests/.gitignore
index 110f2510..bc2748d9 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,6 +1,11 @@
conv
+convertlf
convperf
decperf
+emulatemb
encperf
fbperf
+gesturehandler
hostport
+pixelformat
+unicode
diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx
index 40e3abfc..388dcc95 100644
--- a/tests/perf/encperf.cxx
+++ b/tests/perf/encperf.cxx
@@ -41,6 +41,8 @@
#include <rdr/OutStream.h>
#include <rdr/FileInStream.h>
+#include <rfb/AccessRights.h>
+
#include <rfb/PixelFormat.h>
#include <rfb/CConnection.h>
@@ -134,7 +136,7 @@ public:
void getStats(double&, unsigned long long&, unsigned long long&);
- virtual void setAccessRights(AccessRights ar);
+ virtual void setAccessRights(rfb::AccessRights ar);
virtual void setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
@@ -303,6 +305,7 @@ void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
}
SConn::SConn()
+: SConnection(rfb::AccessDefault)
{
out = new DummyOutStream;
setStreams(NULL, out);
@@ -329,7 +332,7 @@ void SConn::getStats(double& ratio, unsigned long long& bytes,
manager->getStats(ratio, bytes, rawEquivalent);
}
-void SConn::setAccessRights(AccessRights)
+void SConn::setAccessRights(rfb::AccessRights)
{
}
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
index f19123b8..4ec671b8 100644
--- a/unix/vncconfig/vncExt.c
+++ b/unix/vncconfig/vncExt.c
@@ -228,7 +228,7 @@ Bool XVncExtSelectInput(Display* dpy, Window w, int mask)
return True;
}
-Bool XVncExtConnect(Display* dpy, const char* hostAndPort)
+Bool XVncExtConnect(Display* dpy, const char* hostAndPort, Bool viewOnly)
{
xVncExtConnectReq* req;
xVncExtConnectReply rep;
@@ -243,6 +243,7 @@ Bool XVncExtConnect(Display* dpy, const char* hostAndPort)
req->vncExtReqType = X_VncExtConnect;
req->length += (strLen + 3) >> 2;
req->strLen = strLen;
+ req->viewOnly = (CARD8)viewOnly;
Data(dpy, hostAndPort, strLen);
if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
UnlockDisplay(dpy);
diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h
index 2b24469e..4383248c 100644
--- a/unix/vncconfig/vncExt.h
+++ b/unix/vncconfig/vncExt.h
@@ -46,7 +46,7 @@ char* XVncExtGetParamDesc(Display* dpy, const char* param);
char** XVncExtListParams(Display* dpy, int* nParams);
void XVncExtFreeParamList(char** list);
Bool XVncExtSelectInput(Display* dpy, Window w, int mask);
-Bool XVncExtConnect(Display* dpy, const char* hostAndPort);
+Bool XVncExtConnect(Display* dpy, const char* hostAndPort, Bool viewOnly);
Bool XVncExtGetQueryConnect(Display* dpy, char** addr,
char** user, int* timeout, void** opaqueId);
Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve);
@@ -181,7 +181,7 @@ typedef struct {
CARD8 vncExtReqType; /* always VncExtConnect */
CARD16 length B16;
CARD8 strLen;
- CARD8 pad0;
+ CARD8 viewOnly;
CARD16 pad1 B16;
} xVncExtConnectReq;
#define sz_xVncExtConnectReq 8
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
index be8c8195..30d04ca6 100644
--- a/unix/vncconfig/vncconfig.cxx
+++ b/unix/vncconfig/vncconfig.cxx
@@ -177,8 +177,8 @@ static void usage()
{
fprintf(stderr,"usage: %s [parameters]\n",
programName);
- fprintf(stderr," %s [parameters] -connect <host>[:<port>]\n",
- programName);
+ fprintf(stderr," %s [parameters] -connect "
+ "[-view-only] <host>[:<port>]\n", programName);
fprintf(stderr," %s [parameters] -disconnect\n", programName);
fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
programName);
@@ -240,13 +240,18 @@ int main(int argc, char** argv)
if (i < argc) {
for (; i < argc; i++) {
if (strcmp(argv[i], "-connect") == 0) {
+ Bool viewOnly = False;
i++;
+ if (strcmp(argv[i], "-view-only") == 0) {
+ viewOnly = True;
+ i++;
+ }
if (i >= argc) usage();
- if (!XVncExtConnect(dpy, argv[i])) {
+ if (!XVncExtConnect(dpy, argv[i], viewOnly)) {
fprintf(stderr,"connecting to %s failed\n",argv[i]);
}
} else if (strcmp(argv[i], "-disconnect") == 0) {
- if (!XVncExtConnect(dpy, "")) {
+ if (!XVncExtConnect(dpy, "", False)) {
fprintf(stderr,"disconnecting all clients failed\n");
}
} else if (strcmp(argv[i], "-get") == 0) {
diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man
index ed9ddda4..b07c02f4 100644
--- a/unix/vncconfig/vncconfig.man
+++ b/unix/vncconfig/vncconfig.man
@@ -7,7 +7,7 @@ vncconfig \- configure and control a VNC server
.br
.B vncconfig
.RI [ parameters ]
-.B \-connect
+.B \-connect \fP[\fB-view-only\fP]
.IR host [: port ]
.br
.B vncconfig
@@ -55,12 +55,13 @@ is no VNC extension.
.SH OPTIONS
.TP
-.B \-connect \fIhost\fP[:\fIport\fP]
+.B \-connect \fP[\fB-view-only\fP] \fIhost\fP[:\fIport\fP]
Tells an Xvnc server to make a "reverse" connection to a listening VNC viewer
(normally connections are made the other way round - the viewer connects to the
server). \fIhost\fP is the host where the listening viewer is running. If it's
not listening on the default port of 5500, you can specify \fIhost:port\fP
-instead.
+instead. The \fB-view-only\fP option specifies that the server must ignore all
+keyboard or mouse events sent by the client.
.
.TP
.B \-disconnect
diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx
index 93ad6f6f..30091a3d 100644
--- a/unix/vncpasswd/vncpasswd.cxx
+++ b/unix/vncpasswd/vncpasswd.cxx
@@ -23,6 +23,7 @@
#include <config.h>
#endif
+#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
@@ -156,13 +157,16 @@ int main(int argc, char** argv)
}
if (fname[0] == '\0') {
- const char *homeDir = os::getvnchomedir();
- if (homeDir == NULL) {
- fprintf(stderr, "Can't obtain VNC home directory\n");
+ const char *configDir = os::getvncconfigdir();
+ if (configDir == NULL) {
+ fprintf(stderr, "Can't obtain VNC config directory\n");
exit(1);
}
- mkdir(homeDir, 0777);
- snprintf(fname, sizeof(fname), "%s/passwd", homeDir);
+ if (os::mkdir_p(configDir, 0777) == -1) {
+ fprintf(stderr, "Could not create VNC config directory: %s\n", strerror(errno));
+ exit(1);
+ }
+ snprintf(fname, sizeof(fname), "%s/passwd", configDir);
}
while (true) {
diff --git a/unix/vncpasswd/vncpasswd.man b/unix/vncpasswd/vncpasswd.man
index c70a425a..71c6461a 100644
--- a/unix/vncpasswd/vncpasswd.man
+++ b/unix/vncpasswd/vncpasswd.man
@@ -9,11 +9,12 @@ vncpasswd \- change the VNC password
.B vncpasswd
allows you to set the password used to access VNC desktops. Its default
behavior is to prompt for a VNC password and then store an obfuscated version
-of this password to \fIpasswd-file\fR (or to $HOME/.vnc/passwd if no password
-file is specified.) The \fBvncserver\fP script runs \fBvncpasswd\fP the first
-time you start a VNC desktop, and it invokes \fBXvnc\fP with the appropriate
-\fB\-rfbauth\fP option. \fBvncviewer\fP can also be given a password file to
-use via the \fB\-passwd\fP option.
+of this password to \fIpasswd-file\fR (or to
+\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP if no passwordfile is specified.) The
+\fBvncserver\fP script runs \fBvncpasswd\fP the first time you start a VNC
+desktop, and it invokes \fBXvnc\fP with the appropriate \fB\-rfbauth\fP option.
+\fBvncviewer\fP can also be given a password file to use via the \fB\-passwd\fP
+option.
The password must be at least six characters long (unless the \fB\-f\fR
command-line option is used-- see below), and only the first eight
@@ -38,7 +39,9 @@ character.
.SH FILES
.TP
-$HOME/.vnc/passwd
+\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP
+.TQ
+\fI$HOME/.config/tigervnc/passwd\fP
Default location of the VNC password file.
.SH SEE ALSO
diff --git a/unix/vncserver/.gitignore b/unix/vncserver/.gitignore
new file mode 100644
index 00000000..879eae0c
--- /dev/null
+++ b/unix/vncserver/.gitignore
@@ -0,0 +1,5 @@
+vncserver
+vncserver@.service
+vncsession
+vncsession-start
+vncsession.man
diff --git a/unix/vncserver/HOWTO.md b/unix/vncserver/HOWTO.md
index 9f53048e..f422eb2a 100644
--- a/unix/vncserver/HOWTO.md
+++ b/unix/vncserver/HOWTO.md
@@ -30,7 +30,8 @@ To configure Xvnc parameters, you need to go to the same directory where
you did the user mapping and open `vncserver-config-defaults`
configuration file. This file is for the default Xvnc configuration and
will be applied to every user unless any of the following applies:
-* The user has its own configuration in `$HOME/.vnc/config`.
+* The user has its own configuration in `$XDG_CONFIG_HOME/tigervnc/config`
+  or `$HOME/.config/tigervnc/config`.
* The same option with different value is configured in
  `vncserver-config-mandatory` configuration file, which replaces the
  default configuration and has even a higher priority than the per-user
@@ -74,10 +75,10 @@ You need to run it as the user who will run the server.
### Note:
If you used TigerVNC before with your user and you already created a
-password, then you have to make sure the `$HOME/.vnc` folder created by
-`vncpasswd` have the correct *SELinux* context. You either can delete
-this folder and recreate it again by creating the password one more
-time, or alternatively you can run:
+password, then you have to make sure the (legacy, if used) `$HOME/.vnc`
+folder created by `vncpasswd` has the correct *SELinux* context. You
+either can delete this folder and recreate it again by creating the
+password one more time, or alternatively you can run:
```
$ restorecon -RFv /home/<USER>/.vnc
```
diff --git a/unix/vncserver/selinux/.gitignore b/unix/vncserver/selinux/.gitignore
new file mode 100644
index 00000000..965f4ec2
--- /dev/null
+++ b/unix/vncserver/selinux/.gitignore
@@ -0,0 +1,2 @@
+*.pp
+*.pp.bz2
diff --git a/unix/vncserver/selinux/Makefile b/unix/vncserver/selinux/Makefile
index b23f20f6..34869730 100644
--- a/unix/vncserver/selinux/Makefile
+++ b/unix/vncserver/selinux/Makefile
@@ -13,15 +13,16 @@ DATADIR=$(PREFIX)/share
all: vncsession.pp.bz2
%.pp.bz2: %.pp
- bzip2 -9 $^
+ cat "$^" | bzip2 -9 > "$@"
%.pp: %.te
make -f $(DATADIR)/selinux/devel/Makefile $@
+ rm -rf tmp
clean:
rm -f *.pp *.pp.bz2
rm -rf tmp
-install: vncsession.pp.bz2
+install:
mkdir -p $(DESTDIR)$(DATADIR)/selinux/packages/targeted/
install vncsession.pp.bz2 $(DESTDIR)$(DATADIR)/selinux/packages/targeted/vncsession.pp.bz2
diff --git a/unix/vncserver/selinux/vncsession.fc b/unix/vncserver/selinux/vncsession.fc
index bc81f8f2..9ad7d0fb 100644
--- a/unix/vncserver/selinux/vncsession.fc
+++ b/unix/vncserver/selinux/vncsession.fc
@@ -19,6 +19,12 @@
HOME_DIR/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
/root/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+HOME_DIR/\.config/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+/root/\.config/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+HOME_DIR/\.local/share/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+/root/\.local/share/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+HOME_DIR/\.local/state/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+/root/\.local/state/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
/usr/sbin/vncsession -- gen_context(system_u:object_r:vnc_session_exec_t,s0)
/usr/libexec/vncsession-start -- gen_context(system_u:object_r:vnc_session_exec_t,s0)
diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te
index 680be8ea..d92f1bda 100644
--- a/unix/vncserver/selinux/vncsession.te
+++ b/unix/vncserver/selinux/vncsession.te
@@ -37,6 +37,18 @@ allow vnc_session_t self:fifo_file rw_fifo_file_perms;
allow vnc_session_t vnc_session_var_run_t:file manage_file_perms;
files_pid_filetrans(vnc_session_t, vnc_session_var_run_t, file)
+# Allowed to create ~/.local
+optional_policy(`
+ gnome_filetrans_home_content(vnc_session_t)
+')
+optional_policy(`
+ gen_require(`
+ type gconf_home_t;
+ ')
+ create_dirs_pattern(vnc_session_t, gconf_home_t, gconf_home_t)
+')
+
+# Manage TigerVNC files (mainly ~/.local/state/*.log)
create_dirs_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_fifo_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
@@ -72,13 +84,16 @@ optional_policy(`
userdom_spec_domtrans_all_users(vnc_session_t)
userdom_signal_all_users(vnc_session_t)
- userdom_user_home_dir_filetrans(vnc_session_t, vnc_home_t, dir, ".vnc")
- userdom_admin_home_dir_filetrans(vnc_session_t, vnc_home_t, dir, ".vnc")
-
- # This also affects other tools, e.g. vncpasswd
+ # Make sure legacy path has correct type
gen_require(`
attribute userdomain;
+ type gconf_home_t;
')
userdom_admin_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc")
userdom_user_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc")
+
+ gnome_config_filetrans(userdomain, vnc_home_t, dir, "tigervnc")
+ gnome_data_filetrans(userdomain, vnc_home_t, dir, "tigervnc")
+ filetrans_pattern(userdomain, gconf_home_t, vnc_home_t, dir, "tigervnc")
+ filetrans_pattern(vnc_session_t, gconf_home_t, vnc_home_t, dir, "tigervnc")
')
diff --git a/unix/vncserver/tigervnc.pam b/unix/vncserver/tigervnc.pam
index 0f4cb3a7..dda76c49 100644
--- a/unix/vncserver/tigervnc.pam
+++ b/unix/vncserver/tigervnc.pam
@@ -1,4 +1,8 @@
#%PAM-1.0
+
+# THIS IS AN EXAMPLE CONFIGURATION
+# MODIFY AS NEEDED FOR YOUR DISTRIBUTION
+
# pam_selinux.so close should be the first session rule
-session required pam_selinux.so close
session required pam_loginuid.so
diff --git a/unix/vncserver/vncserver-config-defaults b/unix/vncserver/vncserver-config-defaults
index 81d73886..2dc4314e 100644
--- a/unix/vncserver/vncserver-config-defaults
+++ b/unix/vncserver/vncserver-config-defaults
@@ -1,7 +1,7 @@
## Default settings for VNC servers started by the vncserver service
#
# Any settings given here will override the builtin defaults, but can
-# also be overriden by ~/.vnc/config and vncserver-config-mandatory.
+# also be overriden by ~/.config/tigervnc/config and vncserver-config-mandatory.
#
# See HOWTO.md and the following manpages for more details:
# vncsession(8) Xvnc(1)
diff --git a/unix/vncserver/vncserver-config-mandatory b/unix/vncserver/vncserver-config-mandatory
index cfff1bd9..dc716f11 100644
--- a/unix/vncserver/vncserver-config-mandatory
+++ b/unix/vncserver/vncserver-config-mandatory
@@ -1,7 +1,7 @@
## Mandatory settings for VNC servers started by the vncserver service
#
# Any settings given here will override the builtin defaults and
-# settings specified in ~/.vnc/config or vnc-config-defaults.
+# settings specified in ~/.config/tigervnc/config or vnc-config-defaults.
#
# See HOWTO.md and the following manpages for more details:
# vncsession(8) Xvnc(1)
diff --git a/unix/vncserver/vncserver.in b/unix/vncserver/vncserver.in
index 95d672b1..ebdd3a97 100755
--- a/unix/vncserver/vncserver.in
+++ b/unix/vncserver/vncserver.in
@@ -35,7 +35,15 @@
# your site
#
-$vncUserDir = "$ENV{HOME}/.vnc";
+$vncUserDir = rindex("$ENV{XDG_CONFIG_HOME}", "/", 0) == 0
+ ? "$ENV{XDG_CONFIG_HOME}/tigervnc"
+ : "$ENV{HOME}/.config/tigervnc";
+$vncLegacyDir = "$ENV{HOME}/.vnc";
+if (!stat($vncUserDir) && stat($vncLegacyDir)) {
+ warn "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to.";
+ $vncUserDir = $vncLegacyDir;
+}
+
$vncUserConfig = "$vncUserDir/config";
$vncSystemConfigDir = "@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc";
diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c
index ba131fbd..1ee096c7 100644
--- a/unix/vncserver/vncsession.c
+++ b/unix/vncserver/vncsession.c
@@ -259,6 +259,19 @@ stop_pam(pam_handle_t * pamh, int pamret)
return pamret;
}
+static char *
+getenvp(const char *name, char **envp)
+{
+ while (*envp) {
+ size_t varlen;
+ varlen = strcspn(*envp, "=");
+ if (strncmp(*envp, name, varlen) == 0)
+ return *envp + varlen + 1;
+ envp++;
+ }
+ return NULL;
+}
+
static char **
prepare_environ(pam_handle_t * pamh)
{
@@ -345,13 +358,43 @@ switch_user(const char *username, uid_t uid, gid_t gid)
}
}
+static int
+mkdir_p(const char *path_, mode_t mode)
+{
+ char *path = strdup(path_);
+ char *p;
+
+ for (p = path + 1; *p; p++) {
+ if (*p == '/') {
+ *p = '\0';
+ if (mkdir(path, mode) == -1) {
+ if (errno != EEXIST) {
+ free(path);
+ return -1;
+ }
+ }
+ *p = '/';
+ }
+ }
+
+ if (mkdir(path, mode) == -1) {
+ free(path);
+ return -1;
+ }
+
+ free(path);
+
+ return 0;
+}
+
static void
-redir_stdio(const char *homedir, const char *display)
+redir_stdio(const char *homedir, const char *display, char **envp)
{
int fd;
long hostlen;
- char* hostname = NULL;
- char logfile[PATH_MAX];
+ char* hostname = NULL, *xdgstate;
+ char logfile[PATH_MAX], legacy[PATH_MAX];
+ struct stat st;
fd = open("/dev/null", O_RDONLY);
if (fd == -1) {
@@ -364,25 +407,37 @@ redir_stdio(const char *homedir, const char *display)
}
close(fd);
- snprintf(logfile, sizeof(logfile), "%s/.vnc", homedir);
- if (mkdir(logfile, 0755) == -1) {
- if (errno != EEXIST) {
- syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno));
- _exit(EX_OSERR);
- }
+ xdgstate = getenvp("XDG_STATE_HOME", envp);
+ if (xdgstate != NULL && xdgstate[0] == '/')
+ snprintf(logfile, sizeof(logfile), "%s/tigervnc", xdgstate);
+ else
+ snprintf(logfile, sizeof(logfile), "%s/.local/state/tigervnc", homedir);
+
+ snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir);
+ if (stat(logfile, &st) != 0 && stat(legacy, &st) == 0) {
+ syslog(LOG_WARNING, "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to.");
+ strcpy(logfile, legacy);
#ifdef HAVE_SELINUX
+ /* this is only needed to handle historical type changes for the legacy dir */
int result;
- if (selinux_file_context_verify(logfile, 0) == 0) {
- result = selinux_restorecon(logfile, SELINUX_RESTORECON_RECURSE);
+ if (selinux_file_context_verify(legacy, 0) == 0) {
+ result = selinux_restorecon(legacy, SELINUX_RESTORECON_RECURSE);
if (result < 0) {
- syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", logfile, strerror(errno));
+ syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", legacy, strerror(errno));
}
}
#endif
}
+ if (mkdir_p(logfile, 0755) == -1) {
+ if (errno != EEXIST) {
+ syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno));
+ _exit(EX_OSERR);
+ }
+ }
+
hostlen = sysconf(_SC_HOST_NAME_MAX);
if (hostlen < 0) {
syslog(LOG_CRIT, "sysconf(_SC_HOST_NAME_MAX): %s", strerror(errno));
@@ -395,8 +450,8 @@ redir_stdio(const char *homedir, const char *display)
_exit(EX_OSERR);
}
- snprintf(logfile, sizeof(logfile), "%s/.vnc/%s%s.log",
- homedir, hostname, display);
+ snprintf(logfile + strlen(logfile), sizeof(logfile) - strlen(logfile), "/%s%s.log",
+ hostname, display);
free(hostname);
fd = open(logfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
@@ -422,6 +477,10 @@ close_fds(void)
_exit(EX_OSERR);
}
+ // We'll close the file descriptor that the logging uses, so might
+ // as well do it cleanly
+ closelog();
+
while ((entry = readdir(dir)) != NULL) {
int fd;
fd = atoi(entry->d_name);
@@ -466,7 +525,7 @@ run_script(const char *username, const char *display, char **envp)
close_fds();
- redir_stdio(pwent->pw_dir, display);
+ redir_stdio(pwent->pw_dir, display, envp);
// execvpe() is not POSIX and is missing from older glibc
// First clear out everything
@@ -495,9 +554,12 @@ run_script(const char *username, const char *display, char **envp)
child_argv[1] = display;
child_argv[2] = NULL;
+ closelog();
+
execvp(child_argv[0], (char*const*)child_argv);
// execvp failed
+ openlog("vncsession", LOG_PID, LOG_AUTH);
syslog(LOG_CRIT, "execvp: %s", strerror(errno));
_exit(EX_OSERR);
diff --git a/unix/vncserver/vncsession.man.in b/unix/vncserver/vncsession.man.in
index d52da10b..a506ae21 100644
--- a/unix/vncserver/vncsession.man.in
+++ b/unix/vncserver/vncsession.man.in
@@ -27,27 +27,33 @@ debugging in a login shell from a terminal or for running
from a terminal as an ordinary user.
.SH FILES
-Several VNC-related files are found in the directory $HOME/.vnc:
+Several VNC-related files are found in the directory \fI$HOME/.config/tigervnc\fP:
.TP
-@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults
-The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
-and defines options to be passed to Xvnc, they will be used as defaults for
-users. The user's $HOME/.vnc/config overrides settings configured in this file.
-The overall configuration file load order is: this file, $HOME/.vnc/config,
-and then @CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory. None are required to exist.
+\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults\fP
+The optional system-wide equivalent of \fI$HOME/.config/tigervnc/config\fP.
+If this file exists and defines options to be passed to Xvnc, they will be used
+as defaults for users. The user's \fI$HOME/.config/tigervnc/config\fP overrides
+settings configured in this file. The overall configuration file load order is:
+this file, \fI$HOME/.config/tigervnc/config\fP, and then
+\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP.
+None are required to exist.
.TP
-@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory
-The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
-and defines options to be passed to Xvnc, they will override any of the same
-options defined in a user's $HOME/.vnc/config. This file offers a mechanism
-to establish some basic form of system-wide policy. WARNING! There is
-nothing stopping users from constructing their own vncsession-like script
-that calls Xvnc directly to bypass any options defined in
-@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory. The overall configuration file load
-order is: @CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then
-this file. None are required to exist.
+\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP
+The optional system-wide equivalent of \fI$HOME/.config/tigervnc/config\fP.
+If this file exists and defines options to be passed to Xvnc, they will override
+any of the same options defined in a user's \fI$HOME/.config/tigervnc/config\fP.
+This file offers a mechanism to establish some basic form of system-wide policy.
+WARNING! There is nothing stopping users from constructing their own
+vncsession-like script that calls Xvnc directly to bypass any options defined in
+\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP. The
+overall configuration file load order is:
+\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults\fP,
+\fI$HOME/.config/tigervnc/config\fP, and then this file. None are required to
+exist.
.TP
-$HOME/.vnc/config
+\fI$XDG_CONFIG_HOME/tigervnc/config\fP
+.TQ
+\fI$HOME/.config/tigervnc/config\fP
An optional server config file wherein options to be passed to Xvnc are listed
to avoid hard-coding them to the physical invocation. List options in this file
one per line. For those requiring an argument, simply separate the option from
@@ -61,10 +67,14 @@ can be used to control which session type will be started. This should match
one of the files in \fI/usr/share/xsessions\fP. E.g. if there is a file called
"gnome.desktop", then "session=gnome" would be set to use that session type.
.TP
-$HOME/.vnc/passwd
+\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP
+.TQ
+\fI$HOME/.config/tigervnc/passwd\fP
The VNC password file.
.TP
-$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
+\fI$XDG_STATE_HOME/tigervnc/\fIBhost\fI:\fIBdisplay#\fI.log\fP
+.TQ
+\fI$HOME/.local/state/tigervnc/\fIBhost\fI:\fIBdisplay#\fI.log\fP
The log file for Xvnc and the session.
.SH SEE ALSO
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index 1f1f7481..55ea9667 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -26,6 +26,8 @@
#include <signal.h>
#include <unistd.h>
+#include <network/Socket.h>
+
#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index eaf6f901..d4ee16b8 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -323,7 +323,7 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write)
bool XserverDesktop::handleListenerEvent(int fd,
std::list<SocketListener*>* sockets,
- SocketServer* sockserv)
+ VNCServer* sockserv)
{
std::list<SocketListener*>::iterator i;
@@ -344,7 +344,7 @@ bool XserverDesktop::handleListenerEvent(int fd,
}
bool XserverDesktop::handleSocketEvent(int fd,
- SocketServer* sockserv,
+ VNCServer* sockserv,
bool read, bool write)
{
std::list<Socket*> sockets;
@@ -414,10 +414,10 @@ void XserverDesktop::blockHandler(int* timeout)
}
}
-void XserverDesktop::addClient(Socket* sock, bool reverse)
+void XserverDesktop::addClient(Socket* sock, bool reverse, bool viewOnly)
{
vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse);
- server->addSocket(sock, reverse);
+ server->addSocket(sock, reverse, viewOnly ? AccessView : AccessDefault);
vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
}
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index f3c684c7..e604295b 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -42,7 +42,7 @@ namespace rfb {
class VNCServerST;
}
-namespace network { class SocketListener; class Socket; class SocketServer; }
+namespace network { class SocketListener; class Socket; }
class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
public rfb::Timer::Callback {
@@ -75,7 +75,7 @@ public:
void add_copied(const rfb::Region &dest, const rfb::Point &delta);
void handleSocketEvent(int fd, bool read, bool write);
void blockHandler(int* timeout);
- void addClient(network::Socket* sock, bool reverse);
+ void addClient(network::Socket* sock, bool reverse, bool viewOnly);
void disconnectClients();
// QueryConnect methods called from X server code
@@ -110,9 +110,9 @@ public:
protected:
bool handleListenerEvent(int fd,
std::list<network::SocketListener*>* sockets,
- network::SocketServer* sockserv);
+ rfb::VNCServer* sockserv);
bool handleSocketEvent(int fd,
- network::SocketServer* sockserv,
+ rfb::VNCServer* sockserv,
bool read, bool write);
virtual void handleTimeout(rfb::Timer* t);
diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index 075141fa..e43ba150 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -367,7 +367,7 @@ and -once, the Xvnc and associated X clients will die when the user logs out of
the X session in the normal way. It is important to use a VNC password in this
case. A typical entry in inetd.conf might be:
-5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.vnc/passwd
+5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.config/tigervnc/passwd
In fact typically, you would have one entry for each user who uses VNC
regularly, each of whom has their own dedicated TCP port which they use. In
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
index 89c10550..e98275c2 100644
--- a/unix/xserver/hw/vnc/vncExt.c
+++ b/unix/xserver/hw/vnc/vncExt.c
@@ -348,7 +348,7 @@ static int ProcVncExtConnect(ClientPtr client)
address[stuff->strLen] = 0;
rep.success = 0;
- if (vncConnectClient(address) == 0)
+ if (vncConnectClient(address, (int)stuff->viewOnly) == 0)
rep.success = 1;
rep.type = X_Reply;
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index c0610fe8..4003e768 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -267,7 +267,7 @@ void vncExtensionInit(void)
if (scr == 0 && vncInetdSock != -1 && listeners.empty()) {
network::Socket* sock = new network::TcpSocket(vncInetdSock);
- desktop[scr]->addClient(sock, false);
+ desktop[scr]->addClient(sock, false, false);
vlog.info("added inetd sock");
}
}
@@ -343,7 +343,7 @@ void vncSendClipboardData(const char* data)
desktop[scr]->sendClipboardData(data);
}
-int vncConnectClient(const char *addr)
+int vncConnectClient(const char *addr, int viewOnly)
{
if (strlen(addr) == 0) {
try {
@@ -362,7 +362,9 @@ int vncConnectClient(const char *addr)
try {
network::Socket* sock = new network::TcpSocket(host.c_str(), port);
- desktop[0]->addClient(sock, true);
+ vlog.info("Reverse connection: %s:%d%s", host.c_str(), port,
+ viewOnly ? " (view only)" : "");
+ desktop[0]->addClient(sock, true, (bool)viewOnly);
} catch (rdr::Exception& e) {
vlog.error("Reverse connection: %s",e.str());
return -1;
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 9ca00b06..6b37fe62 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -57,7 +57,7 @@ void vncRequestClipboard(void);
void vncAnnounceClipboard(int available);
void vncSendClipboardData(const char* data);
-int vncConnectClient(const char *addr);
+int vncConnectClient(const char *addr, int viewOnly);
void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
const char **address, int *timeout);
diff --git a/vncviewer/.gitignore b/vncviewer/.gitignore
index feba068d..db3cc77d 100644
--- a/vncviewer/.gitignore
+++ b/vncviewer/.gitignore
@@ -1,3 +1,4 @@
vncviewer
vncviewer.desktop.in
vncviewer.desktop
+org.tigervnc.vncviewer.metainfo.xml
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 46821de0..82c4af41 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -280,9 +280,7 @@ void CConn::socketEvent(FL_SOCKET fd, void *data)
when |= FL_WRITE;
Fl::add_fd(fd, when, socketEvent, data);
-
recursing = false;
- Fl::add_fd(fd, FL_READ | FL_EXCEPT, socketEvent, data);
}
////////////////////// CConnection callback methods //////////////////////
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index b85485b2..7d7ae7c3 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -850,11 +850,15 @@ int DesktopWindow::handle(int event)
(Fl::event_y() < 0) || (Fl::event_y() >= h())) {
ungrabPointer();
}
- // We also don't get sensible coordinates on zaphod setups
#if !defined(WIN32) && !defined(__APPLE__)
- if ((fl_xevent != NULL) && (fl_xevent->type == MotionNotify) &&
- (((XMotionEvent*)fl_xevent)->root !=
- XRootWindow(fl_display, fl_screen))) {
+ Window root, child;
+ int x, y, wx, wy;
+ unsigned int mask;
+
+ // We also don't get sensible coordinates on zaphod setups
+ if (XQueryPointer(fl_display, fl_xid(this), &root, &child,
+ &x, &y, &wx, &wy, &mask) &&
+ (root != XRootWindow(fl_display, fl_screen))) {
ungrabPointer();
}
#endif
diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx
index 6a766295..4d57b5fb 100644
--- a/vncviewer/ServerDialog.cxx
+++ b/vncviewer/ServerDialog.cxx
@@ -315,12 +315,12 @@ void ServerDialog::loadServerHistory()
return;
#endif
- const char* homeDir = os::getvnchomedir();
- if (homeDir == NULL)
- throw Exception(_("Could not obtain the home directory path"));
+ const char* stateDir = os::getvncstatedir();
+ if (stateDir == NULL)
+ throw Exception(_("Could not obtain the state directory path"));
char filepath[PATH_MAX];
- snprintf(filepath, sizeof(filepath), "%s/%s", homeDir, SERVER_HISTORY);
+ snprintf(filepath, sizeof(filepath), "%s/%s", stateDir, SERVER_HISTORY);
/* Read server history from file */
FILE* f = fopen(filepath, "r");
@@ -381,12 +381,12 @@ void ServerDialog::saveServerHistory()
return;
#endif
- const char* homeDir = os::getvnchomedir();
- if (homeDir == NULL)
- throw Exception(_("Could not obtain the home directory path"));
+ const char* stateDir = os::getvncstatedir();
+ if (stateDir == NULL)
+ throw Exception(_("Could not obtain the state directory path"));
char filepath[PATH_MAX];
- snprintf(filepath, sizeof(filepath), "%s/%s", homeDir, SERVER_HISTORY);
+ snprintf(filepath, sizeof(filepath), "%s/%s", stateDir, SERVER_HISTORY);
/* Write server history to file */
FILE* f = fopen(filepath, "w+");
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index 75d46dca..15ea4ee8 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -629,11 +629,11 @@ void saveViewerParameters(const char *filename, const char *servername) {
return;
#endif
- const char* homeDir = os::getvnchomedir();
- if (homeDir == NULL)
- throw Exception(_("Could not obtain the home directory path"));
+ const char* configDir = os::getvncconfigdir();
+ if (configDir == NULL)
+ throw Exception(_("Could not obtain the config directory path"));
- snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", homeDir);
+ snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", configDir);
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}
@@ -733,11 +733,11 @@ char* loadViewerParameters(const char *filename) {
return loadFromReg();
#endif
- const char* homeDir = os::getvnchomedir();
- if (homeDir == NULL)
- throw Exception(_("Could not obtain the home directory path"));
+ const char* configDir = os::getvncconfigdir();
+ if (configDir == NULL)
+ throw Exception(_("Could not obtain the config directory path"));
- snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", homeDir);
+ snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", configDir);
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index a5604f76..366327fa 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -37,7 +37,6 @@
#ifdef WIN32
#include <os/winerrno.h>
#include <direct.h>
-#define mkdir(path, mode) _mkdir(path)
#endif
#ifdef __APPLE__
@@ -429,19 +428,6 @@ static void init_fltk()
#endif
}
-static void mkvnchomedir()
-{
- // Create .vnc in the user's home directory if it doesn't already exist
- const char* homeDir = os::getvnchomedir();
- if (homeDir == NULL) {
- vlog.error(_("Could not obtain the home directory path"));
- } else {
- int result = mkdir(homeDir, 0755);
- if (result == -1 && errno != EEXIST)
- vlog.error(_("Could not create VNC home directory: %s"), strerror(errno));
- }
-}
-
static void usage(const char *programName)
{
#ifdef WIN32
@@ -728,7 +714,31 @@ int main(int argc, char** argv)
migrateDeprecatedOptions();
- mkvnchomedir();
+ char *confdir = strdup(os::getvncconfigdir());
+#ifndef WIN32
+ char *dotdir = strrchr(confdir, '.');
+ if (dotdir != NULL && strcmp(dotdir, ".vnc") == 0)
+ vlog.info(_("~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."));
+#else
+ char *vncdir = strrchr(confdir, '\\');
+ if (vncdir != NULL && strcmp(vncdir, "vnc") == 0)
+ vlog.info(_("%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."));
+#endif
+
+ if (os::mkdir_p(os::getvncconfigdir(), 0755) == -1) {
+ if (errno != EEXIST)
+ vlog.error(_("Could not create VNC config directory: %s"), strerror(errno));
+ }
+
+ if (os::mkdir_p(os::getvncdatadir(), 0755) == -1) {
+ if (errno != EEXIST)
+ vlog.error(_("Could not create VNC data directory: %s"), strerror(errno));
+ }
+
+ if (os::mkdir_p(os::getvncstatedir(), 0755) == -1) {
+ if (errno != EEXIST)
+ vlog.error(_("Could not create VNC state directory: %s"), strerror(errno));
+ }
CSecurity::upg = &dlg;
#if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE)
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index 928896a1..1a282126 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -147,19 +147,22 @@ every supported scheme.
.B \-passwd, \-PasswordFile \fIpassword-file\fP
If you are on a filesystem which gives you access to the password file used by
the server, you can specify it here to avoid typing it in. It will usually be
-"~/.vnc/passwd".
+\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP, or \fI~/.config/tigervnc/passwd\fP
+if the former is unset.
.
.TP
.B \-X509CA \fIpath\fP
Path to CA certificate to use when authenticating remote servers using any
of the X509 security schemes (X509None, X509Vnc, etc.). Must be in PEM
-format. Default is \fB$HOME/.vnc/x509_ca.pem\fP.
+format. Default is \fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP, or
+\fI~/.config/tigervnc/x509_ca.pem\fP.
.
.TP
.B \-X509CRL \fIpath\fP
Path to certificate revocation list to use in conjunction with
\fB-X509CA\fP. Must also be in PEM format. Default is
-\fB$HOME/.vnc/x509_crl.pem\fP.
+\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP, or
+\fI~/.config/tigervnc/x509_crl.pem\fP.
.
.TP
.B \-Shared
@@ -338,17 +341,33 @@ re-connect will be offered. Default is on.
.SH FILES
.TP
-$HOME/.vnc/default.tigervnc
+\fI$XDG_CONFIG_HOME/tigervnc/default.tigervnc\fP
+.TQ
+\fI$HOME/.config/tigervnc/default.tigervnc\fP
Default configuration options. This file must have a "magic" first line of
"TigerVNC Configuration file Version 1.0" (without quotes), followed by simple
<setting>=<value> pairs of your choosing. The available settings are those
shown in this man page.
.TP
-$HOME/.vnc/x509_ca.pem
+\fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP
+.TQ
+\fI$HOME/.config/tigervnc/x509_ca.pem\fP
Default CA certificate for authenticating servers.
.TP
-$HOME/.vnc/x509_crl.pem
+\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP
+.TQ
+\fI$HOME/.config/tigervnc/x509_crl.pem\fP
Default certificate revocation list.
+.TP
+\fI$XDG_DATA_HOME/tigervnc/x509_known_hosts\fP
+.TQ
+\fI$HOME/.local/share/tigervnc/x509_known_hosts\fP
+Known hosts database for certificate-based authentication.
+.TP
+\fI$XDG_STATE_HOME/tigervnc/tigervnc.history\fP
+.TQ
+\fI$HOME/.local/state/tigervnc/tigervnc.history\fP
+History file for hostnames that have been recently connected to.
.SH SEE ALSO
.BR Xvnc (1),
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index c2fba0fb..015ba549 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -24,8 +24,12 @@
#include <winsock2.h>
#include <list>
+
+#include <network/Socket.h>
+
#include <rfb/LogWriter.h>
#include <rfb/Timer.h>
+#include <rfb/VNCServer.h>
#include <rfb/util.h>
#include <rfb_win32/SocketManager.h>
@@ -55,7 +59,7 @@ static void requestAddressChangeEvents(network::SocketListener* sock_) {
void SocketManager::addListener(network::SocketListener* sock_,
- network::SocketServer* srvr,
+ VNCServer* srvr,
AddressChangeNotifier* acn) {
WSAEVENT event = WSACreateEvent();
long flags = FD_ACCEPT | FD_CLOSE;
@@ -103,7 +107,7 @@ void SocketManager::remListener(network::SocketListener* sock) {
}
-void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
+void SocketManager::addSocket(network::Socket* sock_, VNCServer* srvr, bool outgoing) {
WSAEVENT event = WSACreateEvent();
if (!event || !addEvent(event, this) ||
(WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
@@ -135,7 +139,7 @@ void SocketManager::remSocket(network::Socket* sock_) {
throw rdr::Exception("Socket not registered");
}
-bool SocketManager::getDisable(network::SocketServer* srvr)
+bool SocketManager::getDisable(VNCServer* srvr)
{
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++) {
@@ -146,7 +150,7 @@ bool SocketManager::getDisable(network::SocketServer* srvr)
throw rdr::Exception("Listener not registered");
}
-void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
+void SocketManager::setDisable(VNCServer* srvr, bool disable)
{
bool found = false;
std::map<HANDLE,ListenInfo>::iterator i;
diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
index e5ca02e6..809c470e 100644
--- a/win/rfb_win32/SocketManager.h
+++ b/win/rfb_win32/SocketManager.h
@@ -19,22 +19,28 @@
// -=- SocketManager.h
// Socket manager class for Win32.
-// Passed a network::SocketListener and a network::SocketServer when
+// Passed a network::SocketListener and a rfb::VNCServer when
// constructed. Uses WSAAsyncSelect to get notifications of network
// connection attempts. When an incoming connection is received,
-// the manager will call network::SocketServer::addClient(). If
+// the manager will call rfb::VNCServer::addClient(). If
// addClient returns true then the manager registers interest in
// network events on that socket, and calls
-// network::SocketServer::processSocketEvent().
+// rfb::VNCServer::processSocketEvent().
#ifndef __RFB_WIN32_SOCKET_MGR_H__
#define __RFB_WIN32_SOCKET_MGR_H__
#include <map>
-#include <network/Socket.h>
#include <rfb_win32/EventManager.h>
+namespace network {
+ class SocketListener;
+ class Socket;
+}
+
namespace rfb {
+ class VNCServer;
+
namespace win32 {
class SocketManager : public EventManager, EventHandler {
@@ -52,21 +58,21 @@ namespace rfb {
};
// Add a listening socket. Incoming connections will be added to the supplied
- // SocketServer.
+ // VNCServer.
void addListener(network::SocketListener* sock_,
- network::SocketServer* srvr,
+ VNCServer* srvr,
AddressChangeNotifier* acn = 0);
// Remove and delete a listening socket.
void remListener(network::SocketListener* sock);
// Add an already-connected socket. Socket events will cause the supplied
- // SocketServer to be called. The socket must ALREADY BE REGISTERED with
- // the SocketServer.
- void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
+ // VNCServer to be called. The socket must ALREADY BE REGISTERED with
+ // the VNCServer.
+ void addSocket(network::Socket* sock_, VNCServer* srvr, bool outgoing=true);
- bool getDisable(network::SocketServer* srvr);
- void setDisable(network::SocketServer* srvr, bool disable);
+ bool getDisable(VNCServer* srvr);
+ void setDisable(VNCServer* srvr, bool disable);
protected:
virtual int checkTimeouts();
@@ -75,11 +81,11 @@ namespace rfb {
struct ConnInfo {
network::Socket* sock;
- network::SocketServer* server;
+ VNCServer* server;
};
struct ListenInfo {
network::SocketListener* sock;
- network::SocketServer* server;
+ VNCServer* server;
AddressChangeNotifier* notifier;
bool disable;
};
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
index a93ca298..1a278678 100644
--- a/win/winvnc/ManagedListener.cxx
+++ b/win/winvnc/ManagedListener.cxx
@@ -45,7 +45,7 @@ ManagedListener::~ManagedListener() {
}
-void ManagedListener::setServer(network::SocketServer* svr) {
+void ManagedListener::setServer(rfb::VNCServer* svr) {
if (svr == server)
return;
vlog.info("set server to %p", svr);
diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
index 39223c79..20503c33 100644
--- a/win/winvnc/ManagedListener.h
+++ b/win/winvnc/ManagedListener.h
@@ -27,7 +27,7 @@ namespace winvnc {
// -=- ManagedListener
// Wrapper class which simplifies the management of a listening socket
- // on a specified port, attached to a SocketManager and SocketServer.
+ // on a specified port, attached to a SocketManager and VNCServer.
// Reopens sockets & reconfigures filters & callbacks as appropriate.
// Handles addition/removal of Listeners from SocketManager internally.
@@ -36,7 +36,7 @@ namespace winvnc {
ManagedListener(rfb::win32::SocketManager* mgr);
~ManagedListener();
- void setServer(network::SocketServer* svr);
+ void setServer(rfb::VNCServer* svr);
void setPort(int port, bool localOnly=false);
void setFilter(const char* filter);
void setAddressChangeNotifier(rfb::win32::SocketManager::AddressChangeNotifier* acn);
@@ -49,7 +49,7 @@ namespace winvnc {
network::TcpFilter* filter;
rfb::win32::SocketManager* manager;
rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;
- network::SocketServer* server;
+ rfb::VNCServer* server;
int port;
bool localOnly;
};
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index a243d95e..38b2ef16 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -363,11 +363,11 @@ void VNCServerWin32::getConnInfo(ListConnInfo * listConn)
if (!conn->authenticated())
status = 3;
- else if (conn->accessCheck(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView))
+ else if (conn->accessCheck(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView))
status = 0;
- else if (conn->accessCheck(rfb::SConnection::AccessView))
+ else if (conn->accessCheck(rfb::AccessView))
status = 1;
else
status = 2;
@@ -398,25 +398,25 @@ void VNCServerWin32::setConnStatus(ListConnInfo* listConn)
if (status == 3) {
conn->close(0);
} else {
- rfb::SConnection::AccessRights ar;
+ rfb::AccessRights ar;
- ar = rfb::SConnection::AccessDefault;
+ ar = rfb::AccessDefault;
switch (status) {
case 0:
- ar |= rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView;
+ ar |= rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView;
break;
case 1:
- ar |= rfb::SConnection::AccessView;
- ar &= ~(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents);
+ ar |= rfb::AccessView;
+ ar &= ~(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents);
break;
case 2:
- ar &= ~(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView);
+ ar &= ~(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView);
break;
}
conn->setAccessRights(ar);