From 8f09de712b53e54d15d2bd5367c10a61c57cda23 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Wed, 6 May 2020 10:37:21 +0200
Subject: Foo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d19b72..78eb93d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,10 @@ if(POLICY CMP0022)
cmake_policy(SET CMP0022 OLD)
endif()
+if(${CMAKE_VERSION} VERSION_LESS "3.4.0")
+ message(WARNING "CMake 3.4.0 or newer is required to get correct default installation paths")
+endif()
+
# Internal cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
@@ -27,17 +31,16 @@ set(VERSION 1.10.1)
set(RCVERSION 1,10,1,0)
# Installation paths
-set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin")
-set(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share")
-set(MAN_DIR "${DATA_DIR}/man")
-set(LOCALE_DIR "${DATA_DIR}/locale")
-set(DOC_DIR "${CMAKE_INSTALL_PREFIX}/share/doc/${CMAKE_PROJECT_NAME}-${VERSION}")
-
-if(WIN32)
-set(BIN_DIR "${CMAKE_INSTALL_PREFIX}")
-set(DOC_DIR "${CMAKE_INSTALL_PREFIX}")
+include(GNUInstallDirs)
+set(CMAKE_INSTALL_UNITDIR "lib/systemd/system" CACHE PATH "systemd unit files (lib/systemd/system)")
+if(IS_ABSOLUTE "${CMAKE_INSTALL_UNITDIR}")
+ set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_UNITDIR}")
+else()
+ set(CMAKE_INSTALL_FULL_UNITDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_UNITDIR}")
endif()
+option(INSTALL_SYSTEMD_UNITS "Install TigerVNC systemd units" ON)
+
if(MSVC)
message(FATAL_ERROR "TigerVNC cannot be built with Visual Studio. Please use MinGW")
endif()
@@ -259,8 +262,7 @@ if(ENABLE_GNUTLS)
endif()
# Check for PAM library
-option(ENABLE_PAM "Enable PAM authentication support" ON)
-if(ENABLE_PAM)
+if(UNIX AND NOT APPLE)
check_include_files(security/pam_appl.h HAVE_PAM_H)
set(CMAKE_REQUIRED_LIBRARIES -lpam)
check_function_exists(pam_start HAVE_PAM_START)
@@ -268,10 +270,9 @@ if(ENABLE_PAM)
if(HAVE_PAM_H AND HAVE_PAM_START)
set(PAM_LIBS pam)
else()
- set(ENABLE_PAM 0)
+ message(FATAL_ERROR "Could not find PAM development files")
endif()
endif()
-set(HAVE_PAM ${ENABLE_PAM})
# Generate config.h and make sure the source finds it
configure_file(config.h.in config.h)
diff --git a/cmake/BuildPackages.cmake b/cmake/BuildPackages.cmake
index ec96318..1f25192 100644
--- a/cmake/BuildPackages.cmake
+++ b/cmake/BuildPackages.cmake
@@ -86,5 +86,5 @@ endif() #UNIX
# Common
#
-install(FILES ${CMAKE_SOURCE_DIR}/LICENCE.TXT DESTINATION ${DOC_DIR})
-install(FILES ${CMAKE_SOURCE_DIR}/README.rst DESTINATION ${DOC_DIR})
+install(FILES ${CMAKE_SOURCE_DIR}/LICENCE.TXT DESTINATION ${CMAKE_INSTALL_FULL_DOCDIR})
+install(FILES ${CMAKE_SOURCE_DIR}/README.rst DESTINATION ${CMAKE_INSTALL_FULL_DOCDIR})
diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake
index e539619..793b190 100644
--- a/cmake/StaticBuild.cmake
+++ b/cmake/StaticBuild.cmake
@@ -115,7 +115,7 @@ endif()
if(BUILD_STATIC_GCC)
# This ensures that we don't depend on libstdc++ or libgcc_s
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nodefaultlibs")
- set(STATIC_BASE_LIBRARIES "-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic")
+ set(STATIC_BASE_LIBRARIES "")
if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE)
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-Bstatic -lasan -Wl,-Bdynamic -ldl -lm -lpthread")
endif()
@@ -135,5 +135,6 @@ if(BUILD_STATIC_GCC)
else()
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lgcc -lgcc_eh -lc")
endif()
- set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${STATIC_BASE_LIBRARIES}")
+ set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} ${STATIC_BASE_LIBRARIES}")
+ set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ${STATIC_BASE_LIBRARIES}")
endif()
diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt
index 8e532a2..689cdcc 100644
--- a/common/rfb/CMakeLists.txt
+++ b/common/rfb/CMakeLists.txt
@@ -75,7 +75,7 @@ endif(WIN32)
set(RFB_LIBRARIES ${JPEG_LIBRARIES} os rdr Xregion)
-if(HAVE_PAM)
+if(UNIX AND NOT APPLE)
set(RFB_SOURCES ${RFB_SOURCES} UnixPasswordValidator.cxx
UnixPasswordValidator.h pam.c pam.h)
set(RFB_LIBRARIES ${RFB_LIBRARIES} ${PAM_LIBS})
diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
index 6f72432..f577c0d 100644
--- a/common/rfb/SSecurityPlain.cxx
+++ b/common/rfb/SSecurityPlain.cxx
@@ -25,10 +25,10 @@
#include <rfb/SConnection.h>
#include <rfb/Exception.h>
#include <rdr/InStream.h>
-#ifdef HAVE_PAM
+#if !defined(WIN32) && !defined(__APPLE__)
#include <rfb/UnixPasswordValidator.h>
#endif
-#ifdef BUILD_WIN
+#ifdef WIN32
#include <rfb/WinPasswdValidator.h>
#endif
@@ -62,10 +62,10 @@ bool PasswordValidator::validUser(const char* username)
SSecurityPlain::SSecurityPlain(SConnection* sc) : SSecurity(sc)
{
-#ifdef HAVE_PAM
- valid = new UnixPasswordValidator();
-#elif BUILD_WIN
+#ifdef WIN32
valid = new WinPasswdValidator();
+#elif !defined(__APPLE__)
+ valid = new UnixPasswordValidator();
#else
valid = NULL;
#endif
diff --git a/common/rfb/UnixPasswordValidator.cxx b/common/rfb/UnixPasswordValidator.cxx
index d096079..ee7bc0d 100644
--- a/common/rfb/UnixPasswordValidator.cxx
+++ b/common/rfb/UnixPasswordValidator.cxx
@@ -25,9 +25,7 @@
#include <rfb/Configuration.h>
#include <rfb/Exception.h>
#include <rfb/UnixPasswordValidator.h>
-#ifdef HAVE_PAM
#include <rfb/pam.h>
-#endif
using namespace rfb;
@@ -43,10 +41,6 @@ bool UnixPasswordValidator::validateInternal(SConnection * sc,
const char *username,
const char *password)
{
-#ifdef HAVE_PAM
CharArray service(strDup(pamService.getData()));
return do_pam_auth(service.buf, username, password);
-#else
- throw AuthFailureException("PAM not supported");
-#endif
}
diff --git a/common/rfb/pam.c b/common/rfb/pam.c
index cb067fd..acac0f4 100644
--- a/common/rfb/pam.c
+++ b/common/rfb/pam.c
@@ -22,9 +22,6 @@
#include <config.h>
#endif
-#ifndef HAVE_PAM
-#error "This source should not be compiled when PAM is unsupported"
-#endif
#include <stdlib.h>
#include <string.h>
diff --git a/common/rfb/pam.h b/common/rfb/pam.h
index 2688f21..d378d19 100644
--- a/common/rfb/pam.h
+++ b/common/rfb/pam.h
@@ -21,14 +21,6 @@
#ifndef __RFB_PAM_H__
#define __RFB_PAM_H__
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifndef HAVE_PAM
-#error "This header should not be included when PAM is unsupported"
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/config.h.in b/config.h.in
index 2d6db9c..2d7a741 100644
--- a/config.h.in
+++ b/config.h.in
@@ -4,10 +4,10 @@
#cmakedefine HAVE_ACTIVE_DESKTOP_H
#cmakedefine HAVE_ACTIVE_DESKTOP_L
#cmakedefine ENABLE_NLS 1
-#cmakedefine HAVE_PAM
-#cmakedefine DATA_DIR "@DATA_DIR@"
-#cmakedefine LOCALE_DIR "@LOCALE_DIR@"
+#cmakedefine CMAKE_INSTALL_FULL_LIBEXECDIR "@CMAKE_INSTALL_FULL_LIBEXECDIR@"
+#cmakedefine CMAKE_INSTALL_FULL_DATADIR "@CMAKE_INSTALL_FULL_DATADIR@"
+#cmakedefine CMAKE_INSTALL_FULL_LOCALEDIR "@CMAKE_INSTALL_FULL_LOCALEDIR@"
/* MS Visual Studio 2008 and newer doesn't know ssize_t */
#if defined(HAVE_GNUTLS) && defined(WIN32) && !defined(__MINGW32__)
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index f61e355..77ec21b 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -7,8 +7,6 @@ endif()
find_package(Java)
-set(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share")
-
set(DEFAULT_JAVACFLAGS "-source 8 -target 8 -encoding UTF-8 -Xlint:all,-serial,-cast,-unchecked,-fallthrough,-dep-ann,-deprecation,-rawtypes")
set(JAVACFLAGS ${DEFAULT_JAVACFLAGS} CACHE STRING
"Java compiler flags (Default: ${DEFAULT_JAVACFLAGS})")
diff --git a/media/CMakeLists.txt b/media/CMakeLists.txt
index 256d435..088c72f 100644
--- a/media/CMakeLists.txt
+++ b/media/CMakeLists.txt
@@ -13,11 +13,11 @@ if(CONVERT_EXECUTABLE)
if(UNIX AND NOT APPLE)
foreach(SIZE 16 22 24 32 48)
install(FILES icons/tigervnc_${SIZE}.png
- DESTINATION ${DATA_DIR}/icons/hicolor/${SIZE}x${SIZE}/apps
+ DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/${SIZE}x${SIZE}/apps
RENAME tigervnc.png)
endforeach()
install(FILES icons/tigervnc.svg
- DESTINATION ${DATA_DIR}/icons/hicolor/scalable/apps)
+ DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps)
endif()
endif()
diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt
index 9c8ddef..2eb10e7 100644
--- a/po/CMakeLists.txt
+++ b/po/CMakeLists.txt
@@ -46,7 +46,7 @@ foreach(lang ${po_FILES})
)
install(FILES ${mo}
- DESTINATION "${LOCALE_DIR}/${lang}/LC_MESSAGES"
+ DESTINATION "${CMAKE_INSTALL_FULL_LOCALEDIR}/${lang}/LC_MESSAGES"
RENAME tigervnc.mo
)
diff --git a/unix/CMakeLists.txt b/unix/CMakeLists.txt
index 7a1457d..5456e00 100644
--- a/unix/CMakeLists.txt
+++ b/unix/CMakeLists.txt
@@ -2,7 +2,5 @@ add_subdirectory(tx)
add_subdirectory(common)
add_subdirectory(vncconfig)
add_subdirectory(vncpasswd)
+add_subdirectory(vncserver)
add_subdirectory(x0vncserver)
-
-install(PROGRAMS vncserver DESTINATION ${BIN_DIR})
-install(FILES vncserver.man DESTINATION ${MAN_DIR}/man1 RENAME vncserver.1)
diff --git a/unix/vncconfig/CMakeLists.txt b/unix/vncconfig/CMakeLists.txt
index 959681f..c3823ab 100644
--- a/unix/vncconfig/CMakeLists.txt
+++ b/unix/vncconfig/CMakeLists.txt
@@ -11,5 +11,5 @@ add_executable(vncconfig
target_link_libraries(vncconfig tx rfb network rdr ${X11_LIBRARIES})
-install(TARGETS vncconfig DESTINATION ${BIN_DIR})
-install(FILES vncconfig.man DESTINATION ${MAN_DIR}/man1 RENAME vncconfig.1)
+install(TARGETS vncconfig DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+install(FILES vncconfig.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1 RENAME vncconfig.1)
diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man
index b685a46..ed9ddda 100644
--- a/unix/vncconfig/vncconfig.man
+++ b/unix/vncconfig/vncconfig.man
@@ -111,8 +111,8 @@ When run as a "helper" app, make the window iconified at startup.
.SH SEE ALSO
.BR vncpasswd (1),
.BR vncviewer (1),
-.BR vncserver (1),
-.BR Xvnc (1)
+.BR Xvnc (1),
+.BR vncsession (8)
.br
https://www.tigervnc.org
diff --git a/unix/vncpasswd/CMakeLists.txt b/unix/vncpasswd/CMakeLists.txt
index a04ed0b..9f716fa 100644
--- a/unix/vncpasswd/CMakeLists.txt
+++ b/unix/vncpasswd/CMakeLists.txt
@@ -5,5 +5,5 @@ add_executable(vncpasswd
target_link_libraries(vncpasswd tx rfb os)
-install(TARGETS vncpasswd DESTINATION ${BIN_DIR})
-install(FILES vncpasswd.man DESTINATION ${MAN_DIR}/man1 RENAME vncpasswd.1)
+install(TARGETS vncpasswd DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+install(FILES vncpasswd.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1 RENAME vncpasswd.1)
diff --git a/unix/vncpasswd/vncpasswd.man b/unix/vncpasswd/vncpasswd.man
index 9e68181..c70a425 100644
--- a/unix/vncpasswd/vncpasswd.man
+++ b/unix/vncpasswd/vncpasswd.man
@@ -43,9 +43,9 @@ Default location of the VNC password file.
.SH SEE ALSO
.BR vncviewer (1),
-.BR vncserver (1),
.BR Xvnc (1)
.BR vncconfig (1),
+.BR vncsession (8)
.br
https://www.tigervnc.org
diff --git a/unix/vncserver.man b/unix/vncserver.man
deleted file mode 100644
index 95f7960..0000000
--- a/unix/vncserver.man
+++ /dev/null
@@ -1,204 +0,0 @@
-.TH vncserver 1 "" "TigerVNC" "Virtual Network Computing"
-.SH NAME
-vncserver \- start or stop a VNC server
-.SH SYNOPSIS
-.B vncserver
-.RI [: display# ]
-.RB [ \-name
-.IR desktop-name ]
-.RB [ \-geometry
-.IR width x height ]
-.RB [ \-depth
-.IR depth ]
-.RB [ \-pixelformat
-.IR format ]
-.RB [ \-fp
-.IR font-path ]
-.RB [ \-fg ]
-.RB [ \-autokill ]
-.RB [ \-noxstartup ]
-.RB [ \-xstartup
-.IR script ]
-.RI [ Xvnc-options... ]
-.br
-.BI "vncserver \-kill :" display#
-.br
-.BI "vncserver \-list"
-.SH DESCRIPTION
-.B vncserver
-is used to start a VNC (Virtual Network Computing) desktop.
-.B vncserver
-is a Perl script which simplifies the process of starting an Xvnc server. It
-runs Xvnc with appropriate options and starts a window manager on the VNC
-desktop.
-
-.B vncserver
-can be run with no options at all. In this case it will choose the first
-available display number (usually :1), start Xvnc with that display number,
-and start the default window manager in the Xvnc session. You can also
-specify the display number, in which case vncserver will attempt to start
-Xvnc with that display number and exit if the display number is not
-available. For example:
-
-.RS
-vncserver :13
-.RE
-
-Editing the file $HOME/.vnc/xstartup allows you to change the applications run
-at startup (but note that this will not affect an existing VNC session.)
-
-.SH OPTIONS
-You can get a list of options by passing \fB\-h\fP as an option to vncserver.
-In addition to the options listed below, any unrecognised options will be
-passed to Xvnc - see the Xvnc man page, or "Xvnc \-help", for details.
-
-.TP
-.B \-name \fIdesktop-name\fP
-Each VNC desktop has a name which may be displayed by the viewer. The desktop
-name defaults to "\fIhost\fP:\fIdisplay#\fP (\fIusername\fP)", but you can
-change it with this option. The desktop name option is passed to the xstartup
-script via the $VNCDESKTOP environment variable, which allows you to run a
-different set of applications depending on the name of the desktop.
-.
-.TP
-.B \-geometry \fIwidth\fPx\fIheight\fP
-Specify the size of the VNC desktop to be created. Default is 1024x768.
-.
-.TP
-.B \-depth \fIdepth\fP
-Specify the pixel depth (in bits) of the VNC desktop to be created. Default is
-24. Other possible values are 8, 15 and 16 - anything else is likely to cause
-strange behaviour by applications.
-.
-.TP
-.B \-pixelformat \fIformat\fP
-Specify pixel format for Xvnc to use (BGRnnn or RGBnnn). The default for
-depth 8 is BGR233 (meaning the most significant two bits represent blue, the
-next three green, and the least significant three represent red), the default
-for depth 16 is RGB565, and the default for depth 24 is RGB888.
-.
-.TP
-.B \-cc 3
-As an alternative to the default TrueColor visual, this allows you to run an
-Xvnc server with a PseudoColor visual (i.e. one which uses a color map or
-palette), which can be useful for running some old X applications which only
-work on such a display. Values other than 3 (PseudoColor) and 4 (TrueColor)
-for the \-cc option may result in strange behaviour, and PseudoColor desktops
-must have an 8-bit depth.
-.
-.TP
-.B \-kill :\fIdisplay#\fP
-This kills a VNC desktop previously started with vncserver. It does this by
-killing the Xvnc process, whose process ID is stored in the file
-"$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.pid". The
-.B \-kill
-option ignores anything preceding the first colon (":") in the display
-argument. Thus, you can invoke "vncserver \-kill $DISPLAY", for example at the
-end of your xstartup file after a particular application exits.
-.
-.TP
-.B \-fp \fIfont-path\fP
-If the vncserver script detects that the X Font Server (XFS) is running, it
-will attempt to start Xvnc and configure Xvnc to use XFS for font handling.
-Otherwise, if XFS is not running, the vncserver script will attempt to start
-Xvnc and allow Xvnc to use its own preferred method of font handling (which may
-be a hard-coded font path or, on more recent systems, a font catalog.) In
-any case, if Xvnc fails to start, the vncserver script will then attempt to
-determine an appropriate X font path for this system and start Xvnc using
-that font path.
-
-The
-.B \-fp
-argument allows you to override the above fallback logic and specify a font
-path for Xvnc to use.
-.
-.TP
-.B \-fg
-Runs Xvnc as a foreground process. This has two effects: (1) The VNC server
-can be aborted with CTRL-C, and (2) the VNC server will exit as soon as the
-user logs out of the window manager in the VNC session. This may be necessary
-when launching TigerVNC from within certain grid computing environments.
-.
-.TP
-.B \-autokill
-Automatically kill Xvnc whenever the xstartup script exits. In most cases,
-this has the effect of terminating Xvnc when the user logs out of the window
-manager.
-.
-.TP
-.B \-noxstartup
-Do not run the %HOME/.vnc/xstartup script after launching Xvnc. This
-option allows you to manually start a window manager in your TigerVNC session.
-.
-.TP
-.B \-xstartup \fIscript\fP
-Run a custom startup script, instead of %HOME/.vnc/xstartup, after launching
-Xvnc. This is useful to run full-screen applications.
-.
-.TP
-.B \-list
-Lists all VNC desktops started by vncserver.
-
-.SH FILES
-Several VNC-related files are found in the directory $HOME/.vnc:
-.TP
-$HOME/.vnc/xstartup
-A shell script specifying X applications to be run when a VNC desktop is
-started. If this file does not exist, then vncserver will create a default
-xstartup script which attempts to launch your chosen window manager.
-.TP
-/etc/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 /etc/tigervnc/vncserver-config-mandatory. None are required to exist.
-.TP
-/etc/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 vncserver-like script
-that calls Xvnc directly to bypass any options defined in
-/etc/tigervnc/vncserver-config-mandatory. Likewise, any CLI arguments passed
-to vncserver will override ANY config file setting of the same name. The
-overall configuration file load order is:
-/etc/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then this file.
-None are required to exist.
-.TP
-$HOME/.vnc/config
-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
-the argument with an equal sign, for example: "geometry=2000x1200" or
-"securitytypes=vncauth,tlsvnc". Options without an argument are simply listed
-as a single word, for example: "localhost" or "alwaysshared".
-.TP
-$HOME/.vnc/passwd
-The VNC password file.
-.TP
-$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
-The log file for Xvnc and applications started in xstartup.
-.TP
-$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.pid
-Identifies the Xvnc process ID, used by the
-.B \-kill
-option.
-
-.SH SEE ALSO
-.BR vncviewer (1),
-.BR vncpasswd (1),
-.BR vncconfig (1),
-.BR Xvnc (1)
-.br
-https://www.tigervnc.org
-
-.SH AUTHOR
-Tristan Richardson, RealVNC Ltd., D. R. Commander and others.
-
-VNC was originally developed by the RealVNC team while at Olivetti
-Research Ltd / AT&T Laboratories Cambridge. TightVNC additions were
-implemented by Constantin Kaplinsky. Many other people have since
-participated in development, testing and support. This manual is part
-of the TigerVNC software suite.
diff --git a/unix/vncserver/CMakeLists.txt b/unix/vncserver/CMakeLists.txt
new file mode 100644
index 0000000..eeb4b7b
--- /dev/null
+++ b/unix/vncserver/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_executable(vncsession vncsession.c)
+target_link_libraries(vncsession ${PAM_LIBS})
+
+configure_file(vncserver@.service.in vncserver@.service @ONLY)
+configure_file(vncsession-start.in vncsession-start @ONLY)
+configure_file(vncserver.in vncserver @ONLY)
+
+install(TARGETS vncsession DESTINATION ${CMAKE_INSTALL_FULL_SBINDIR})
+install(FILES tigervnc.pam DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/pam.d RENAME tigervnc)
+install(FILES vncsession.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man8 RENAME vncsession.8)
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncserver DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
+install(FILES vncserver.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man8 RENAME vncserver.8)
+install(FILES vncserver-config-defaults vncserver-config-mandatory DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/tigervnc)
+
+install(FILES vncserver.users DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/tigervnc)
+
+if(INSTALL_SYSTEMD_UNITS)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/vncserver@.service DESTINATION ${CMAKE_INSTALL_FULL_UNITDIR})
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncsession-start DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
+endif()
diff --git a/unix/vncserver/selinux/Makefile b/unix/vncserver/selinux/Makefile
new file mode 100644
index 0000000..904a2d5
--- /dev/null
+++ b/unix/vncserver/selinux/Makefile
@@ -0,0 +1,24 @@
+# SELinux module for TigerVNC's vncsession
+#
+# This will install the policy module, but not load it. To apply
+# it you should also run:
+#
+# sudo semodule -i /usr/share/selinux/packages/vncsession.pp
+# sudo restorecon /usr/sbin/vncsession /usr/libexec/vncsession-start
+#
+
+PREFIX=/usr
+DATADIR=$(PREFIX)/share
+
+all: vncsession.pp
+
+%.pp: %.te
+ make -f $(DATADIR)/selinux/devel/Makefile $@
+
+clean:
+ rm -f *.pp
+ rm -rf tmp
+
+install: vncsession.pp
+ mkdir -p $(DESTDIR)$(DATADIR)/selinux/packages
+ install vncsession.pp $(DESTDIR)$(DATADIR)/selinux/packages/vncsession.pp
diff --git a/unix/vncserver/selinux/vncsession.fc b/unix/vncserver/selinux/vncsession.fc
new file mode 100644
index 0000000..121cdd2
--- /dev/null
+++ b/unix/vncserver/selinux/vncsession.fc
@@ -0,0 +1,26 @@
+#
+# Copyright 2018 Pierre Ossman for Cendio AB
+#
+# 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.
+#
+
+HOME_DIR/\.vnc(/.*)? gen_context(system_u:object_r:xdm_home_t,s0)
+HOME_ROOT/\.vnc(/.*)? gen_context(system_u:object_r:xdm_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)
+
+/var/run/vncsession-:[0-9]*\.pid -- gen_context(system_u:object_r:vnc_session_var_run_t,s0)
diff --git a/unix/vncserver/selinux/vncsession.if b/unix/vncserver/selinux/vncsession.if
new file mode 100644
index 0000000..3eb6a30
--- /dev/null
+++ b/unix/vncserver/selinux/vncsession.if
@@ -0,0 +1 @@
+## <summary></summary>
diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te
new file mode 100644
index 0000000..941f28d
--- /dev/null
+++ b/unix/vncserver/selinux/vncsession.te
@@ -0,0 +1,67 @@
+#
+# Copyright 2018-2020 Pierre Ossman for Cendio AB
+#
+# 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.
+#
+
+policy_module(vncsession, 1.0.0);
+
+gen_require(`
+ type unconfined_t;
+ type xdm_home_t;
+')
+
+type vnc_session_exec_t;
+corecmd_executable_file(vnc_session_exec_t)
+type vnc_session_t;
+init_daemon_domain(vnc_session_t, vnc_session_exec_t)
+auth_login_pgm_domain(vnc_session_t)
+
+type vnc_session_var_run_t;
+files_pid_file(vnc_session_var_run_t)
+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)
+
+auth_write_login_records(vnc_session_t)
+
+can_exec(vnc_session_t, vnc_session_exec_t)
+
+userdom_spec_domtrans_all_users(vnc_session_t)
+userdom_signal_all_users(vnc_session_t)
+
+allow vnc_session_t self:capability { kill chown dac_override dac_read_search fowner setgid setuid sys_resource };
+allow vnc_session_t self:process { getcap setsched setexec setrlimit };
+allow vnc_session_t self:fifo_file rw_fifo_file_perms;
+
+manage_files_pattern(vnc_session_t, xdm_home_t, xdm_home_t)
+manage_fifo_files_pattern(vnc_session_t, xdm_home_t, xdm_home_t)
+manage_sock_files_pattern(vnc_session_t, xdm_home_t, xdm_home_t)
+manage_lnk_files_pattern(vnc_session_t, xdm_home_t, xdm_home_t)
+
+userdom_user_home_dir_filetrans(unconfined_t, xdm_home_t, dir, ".vnc")
+userdom_user_home_dir_filetrans(vnc_session_t, xdm_home_t, dir, ".vnc")
+
+userdom_admin_home_dir_filetrans(vnc_session_t, xdm_home_t, dir, ".vnc")
+userdom_admin_home_dir_filetrans(unconfined_t, xdm_home_t, dir, ".vnc")
+
+miscfiles_read_localization(vnc_session_t)
+
+kernel_read_kernel_sysctls(vnc_session_t)
+
+logging_append_all_logs(vnc_session_t)
+
+mcs_process_set_categories(vnc_session_t)
+mcs_killall(vnc_session_t)
diff --git a/unix/vncserver/tigervnc.pam b/unix/vncserver/tigervnc.pam
new file mode 100644
index 0000000..0f4cb3a
--- /dev/null
+++ b/unix/vncserver/tigervnc.pam
@@ -0,0 +1,11 @@
+#%PAM-1.0
+# pam_selinux.so close should be the first session rule
+-session required pam_selinux.so close
+session required pam_loginuid.so
+-session required pam_selinux.so open
+session required pam_namespace.so
+session optional pam_keyinit.so force revoke
+session required pam_limits.so
+-session optional pam_systemd.so
+session required pam_unix.so
+-session optional pam_reauthorize.so prepare
diff --git a/unix/vncserver/vncserver-config-defaults b/unix/vncserver/vncserver-config-defaults
new file mode 100644
index 0000000..0c217bf
--- /dev/null
+++ b/unix/vncserver/vncserver-config-defaults
@@ -0,0 +1,15 @@
+## 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.
+#
+# See the following manpages for more details: vncserver(1) Xvnc(1)
+#
+# Several common settings are shown below. Uncomment and modify to your
+# liking.
+
+# securitytypes=vncauth,tlsvnc
+# desktop=sandbox
+# geometry=2000x1200
+# localhost
+# alwaysshared
diff --git a/unix/vncserver/vncserver-config-mandatory b/unix/vncserver/vncserver-config-mandatory
new file mode 100644
index 0000000..98c32f6
--- /dev/null
+++ b/unix/vncserver/vncserver-config-mandatory
@@ -0,0 +1,15 @@
+## 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.
+#
+# See the following manpages for more details: vncserver(1) Xvnc(1)
+#
+# Several common settings are shown below. Uncomment and modify to your
+# liking.
+
+# securitytypes=vncauth,tlsvnc
+# desktop=sandbox
+# geometry=2000x1200
+# localhost
+# alwaysshared
diff --git a/unix/vncserver/vncserver.in b/unix/vncserver/vncserver.in
new file mode 100755
index 0000000..8e05b72
--- /dev/null
+++ b/unix/vncserver/vncserver.in
@@ -0,0 +1,485 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2015-2019 Pierre Ossman for Cendio AB
+# Copyright (C) 2009-2010 D. R. Commander. All Rights Reserved.
+# Copyright (C) 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+# Copyright (C) 2002-2003 Constantin Kaplinsky. All Rights Reserved.
+# Copyright (C) 2002-2005 RealVNC Ltd.
+# Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+#
+# This is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+#
+# vncserver - wrapper script to start an X VNC server.
+#
+
+&SanityCheck();
+
+#
+# Global variables. You may want to configure some of these for
+# your site
+#
+
+$vncUserDir = "$ENV{HOME}/.vnc";
+$vncUserConfig = "$vncUserDir/config";
+
+$vncSystemConfigDir = "/etc/tigervnc";
+$vncSystemConfigDefaultsFile = "$vncSystemConfigDir/vncserver-config-defaults";
+$vncSystemConfigMandatoryFile = "$vncSystemConfigDir/vncserver-config-mandatory";
+
+$xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
+
+chop($host = `uname -n`);
+
+if (-d "/etc/X11/fontpath.d") {
+ $fontPath = "catalogue:/etc/X11/fontpath.d";
+}
+
+@fontpaths = ('/usr/share/X11/fonts', '/usr/share/fonts', '/usr/share/fonts/X11/');
+if (! -l "/usr/lib/X11") {push(@fontpaths, '/usr/lib/X11/fonts');}
+if (! -l "/usr/X11") {push(@fontpaths, '/usr/X11/lib/X11/fonts');}
+if (! -l "/usr/X11R6") {push(@fontpaths, '/usr/X11R6/lib/X11/fonts');}
+push(@fontpaths, '/usr/share/fonts/default');
+
+@fonttypes = ('misc',
+ '75dpi',
+ '100dpi',
+ 'Speedo',
+ 'Type1');
+
+foreach $_fpath (@fontpaths) {
+ foreach $_ftype (@fonttypes) {
+ if (-f "$_fpath/$_ftype/fonts.dir") {
+ if (! -l "$_fpath/$_ftype") {
+ $defFontPath .= "$_fpath/$_ftype,";
+ }
+ }
+ }
+}
+
+if ($defFontPath) {
+ if (substr($defFontPath, -1, 1) == ',') {
+ chop $defFontPath;
+ }
+}
+
+if ($fontPath eq "") {
+ $fontPath = $defFontPath;
+}
+
+# Find display number.
+if ((@ARGV == 1) && ($ARGV[0] =~ /^:(\d+)$/)) {
+ $displayNumber = $1;
+ if (!&CheckDisplayNumber($displayNumber)) {
+ die "A VNC server is already running as :$displayNumber\n";
+ }
+} else {
+ &Usage();
+}
+
+$vncPort = 5900 + $displayNumber;
+
+$desktopName = "$host:$displayNumber ($ENV{USER})";
+
+my %default_opts;
+my %config;
+
+# We set some reasonable defaults. Config file settings
+# override these where present.
+$default_opts{desktop} = $desktopName;
+$default_opts{auth} = $xauthorityFile;
+$default_opts{rfbwait} = 30000;
+$default_opts{rfbauth} = "$vncUserDir/passwd";
+$default_opts{rfbport} = $vncPort;
+$default_opts{fp} = $fontPath if ($fontPath);
+$default_opts{pn} = "";
+
+# Load user-overrideable system defaults
+LoadConfig($vncSystemConfigDefaultsFile);
+
+# Then the user's settings
+LoadConfig($vncUserConfig);
+
+# And then override anything set above if mandatory settings exist.
+# WARNING: "Mandatory" is used loosely here! As the man page says,
+# there is nothing stopping someone from EASILY subverting the
+# settings in $vncSystemConfigMandatoryFile by simply passing
+# CLI args to vncserver, which trump config files! To properly
+# hard force policy in a non-subvertible way would require major
+# development work that touches Xvnc itself.
+LoadConfig($vncSystemConfigMandatoryFile, 1);
+
+#
+# Check whether VNC authentication is enabled, and if so, check that
+# a VNC password has been created.
+#
+
+$securityTypeArgSpecified = 0;
+$vncAuthEnabled = 0;
+$passwordArgSpecified = 0;
+@vncAuthStrings = ("vncauth", "tlsvnc", "x509vnc");
+
+# ...first we check our configuration files' settings
+if ($config{'securitytypes'}) {
+ $securityTypeArgSpecified = 1;
+ foreach $arg2 (split(',', $config{'securitytypes'})) {
+ if (grep {$_ eq lc($arg2)} @vncAuthStrings) {
+ $vncAuthEnabled = 1;
+ }
+ }
+}
+
+if ($config{'password'} ||
+ $config{'passwordfile'} ||
+ $config{'rfbauth'}) {
+ $passwordArgSpecified = 1;
+}
+
+if ((!$securityTypeArgSpecified || $vncAuthEnabled) && !$passwordArgSpecified) {
+ ($z,$z,$mode) = stat("$vncUserDir/passwd");
+ if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
+ die "VNC authentication enabled, but no password file created.\n";
+ }
+}
+
+#
+# Find a desktop session to run
+#
+
+my $sessionname;
+my %session;
+
+$sessionname = delete $config{'session'};
+
+if ($sessionname) {
+ %session = LoadXSession($sessionname);
+ if (!%session) {
+ warn "Could not load configured desktop session $sessionname\n";
+ $sessionname = undef;
+ }
+}
+
+if (!$sessionname) {
+ foreach $file (glob("/usr/share/xsessions/*.desktop")) {
+ ($name) = $file =~ /^.*\/(.*)[.]desktop$/;
+ %session = LoadXSession($name);
+ if (%session) {
+ $sessionname = $name;
+ last;
+ }
+ }
+}
+
+if (!$sessionname) {
+ die "Could not find a desktop session to run\n";
+}
+
+warn "Using desktop session $sessionname\n";
+
+if (!$session{'Exec'}) {
+ die "No command specified for desktop session\n";
+}
+
+$ENV{GDMSESSION} = $sessionname;
+$ENV{DESKTOP_SESSION} = $sessionname;
+$ENV{XDG_SESSION_DESKTOP} = $sessionname;
+
+if ($session{'DesktopNames'}) {
+ $ENV{XDG_DESKTOP_NAMES} = $session{'DesktopNames'} =~ s/;/:/gr;
+}
+
+
+# Make an X server cookie and set up the Xauthority file
+# mcookie is a part of util-linux, usually only GNU/Linux systems have it.
+$cookie = `mcookie`;
+# Fallback for non GNU/Linux OS - use /dev/urandom on systems that have it,
+# otherwise use perl's random number generator, seeded with the sum
+# of the current time, our PID and part of the encrypted form of the password.
+if ($cookie eq "" && open(URANDOM, '<', '/dev/urandom')) {
+ my $randata;
+ if (sysread(URANDOM, $randata, 16) == 16) {
+ $cookie = unpack 'h*', $randata;
+ }
+ close(URANDOM);
+}
+if ($cookie eq "") {
+ srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
+ for (1..16) {
+ $cookie .= sprintf("%02x", int(rand(256)) % 256);
+ }
+}
+
+open(XAUTH, "|xauth -f $xauthorityFile source -");
+print XAUTH "add $host:$displayNumber . $cookie\n";
+print XAUTH "add $host/unix:$displayNumber . $cookie\n";
+close(XAUTH);
+
+$ENV{XAUTHORITY} = $xauthorityFile;
+
+# Now start the X VNC Server
+
+@cmd = ("xinit");
+
+push(@cmd, $Xsession, $session{'Exec'});
+
+push(@cmd, '--');
+
+
+# We build up our Xvnc command with options
+push(@cmd, "@CMAKE_INSTALL_FULL_BINDIR@/Xvnc", ":$displayNumber");
+
+foreach my $k (sort keys %config) {
+ push(@cmd, "-$k");
+ push(@cmd, $config{$k}) if $config{$k};
+ delete $default_opts{$k}; # file options take precedence
+}
+
+foreach my $k (sort keys %default_opts) {
+ push(@cmd, "-$k");
+ push(@cmd, $default_opts{$k}) if $default_opts{$k};
+}
+
+warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
+
+warn "Starting desktop session $sessionname\n";
+
+exec(@cmd);
+
+die "Failed to start session.\n";
+
+###############################################################################
+# Functions
+###############################################################################
+
+#
+# Populate the global %config hash with settings from a specified
+# vncserver configuration file if it exists
+#
+# Args: 1. file path
+# 2. optional boolean flag to enable warning when a previously
+# set configuration setting is being overridden
+#
+sub LoadConfig {
+ local ($configFile, $warnoverride) = @_;
+ local ($toggle) = undef;
+
+ if (stat($configFile)) {
+ if (open(IN, $configFile)) {
+ while (<IN>) {
+ next if /^#/;
+ if (my ($k, $v) = /^\s*(\w+)\s*=\s*(.+)$/) {
+ $k = lc($k); # must normalize key case
+ if ($warnoverride && $config{$k}) {
+ print("Warning: $configFile is overriding previously defined '$k' to be '$v'\n");
+ }
+ $config{$k} = $v;
+ } elsif ($_ =~ m/^\s*(\S+)/) {
+ # We can't reasonably warn on override of toggles (e.g. AlwaysShared)
+ # because it would get crazy to do so. We'd have to check if the
+ # current config file being loaded defined the logical opposite setting
+ # (NeverShared vs. AlwaysShared, etc etc).
+ $toggle = lc($1); # must normalize key case
+ $config{$toggle} = $k;
+ }
+ }
+ close(IN);
+ }
+ }
+}
+
+
+#
+# Load a session desktop file
+#
+sub LoadXSession {
+ local ($name) = @_;
+ my $file, $found_group, %session;
+
+ $file = "/usr/share/xsessions/$name.desktop";
+
+ if (!stat($file)) {
+ warn "Could not find session desktop file $file";
+ return;
+ }
+
+ if (!open(IN, $file)) {
+ warn "Could not open session desktop file $file";
+ return;
+ }
+
+ $found_group = 0;
+ while (my $line = <IN>) {
+ next if $line =~ /^#/;
+ next if $line =~ /^\s*$/;
+
+ if (!$found_group) {
+ next if $line != "[Desktop Entry]";
+ $found_group = 1;
+ next;
+ } else {
+ last if $line =~ /^\[/;
+ }
+
+ my ($key, $value) = $line =~ /^\s*([]A-Za-z0-9_@\-\[]+)\s*=\s*(.*)$/;
+ if (!$key) {
+ warn "Invalid session desktop file $file";
+ close(IN);
+ return;
+ }
+
+ $value =~ s/\\s/ /g;
+ $value =~ s/\\n/\n/g;
+ $value =~ s/\\t/\t/g;
+ $value =~ s/\\r/\r/g;
+ $value =~ s/\\\\/\\/g;
+
+ $session{$key} = $value;
+ }
+
+ close(IN);
+
+ return %session;
+}
+
+
+#
+# CheckDisplayNumber checks if the given display number is available. A
+# display number n is taken if something is listening on the VNC server port
+# (5900+n) or the X server port (6000+n).
+#
+
+sub CheckDisplayNumber
+{
+ local ($n) = @_;
+
+ socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
+ eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
+ if (!bind(S, pack('S n x12', $AF_INET, 6000 + $n))) {
+ close(S);
+ return 0;
+ }
+ close(S);
+
+ socket(S, $AF_INET, $SOCK_STREAM, 0) || die "$prog: socket failed: $!\n";
+ eval 'setsockopt(S, &SOL_SOCKET, &SO_REUSEADDR, pack("l", 1))';
+ if (!bind(S, pack('S n x12', $AF_INET, 5900 + $n))) {
+ close(S);
+ return 0;
+ }
+ close(S);
+
+ if (-e "/tmp/.X$n-lock") {
+ warn "\nWarning: $host:$n is taken because of /tmp/.X$n-lock\n";
+ warn "Remove this file if there is no X server $host:$n\n";
+ return 0;
+ }
+
+ if (-e "/tmp/.X11-unix/X$n") {
+ warn "\nWarning: $host:$n is taken because of /tmp/.X11-unix/X$n\n";
+ warn "Remove this file if there is no X server $host:$n\n";
+ return 0;
+ }
+
+ if (-e "/usr/spool/sockets/X11/$n") {
+ warn("\nWarning: $host:$n is taken because of ".
+ "/usr/spool/sockets/X11/$n\n");
+ warn "Remove this file if there is no X server $host:$n\n";
+ return 0;
+ }
+
+ return 1;
+}
+
+#
+# Usage
+#
+
+sub Usage
+{
+ die("\nusage: $prog <display>\n\n");
+}
+
+
+# Routine to make sure we're operating in a sane environment.
+sub SanityCheck
+{
+ local ($cmd);
+
+ # Get the program name
+ ($prog) = ($0 =~ m|([^/]+)$|);
+
+ #
+ # Check we have all the commands we'll need on the path.
+ #
+
+ cmd:
+ foreach $cmd ("uname","xauth","xinit") {
+ for (split(/:/,$ENV{PATH})) {
+ if (-x "$_/$cmd") {
+ next cmd;
+ }
+ }
+ die "$prog: couldn't find \"$cmd\" on your PATH.\n";
+ }
+
+ foreach $cmd ("/etc/X11/xinit/Xsession", "/etc/X11/Xsession") {
+ if (-x "$cmd") {
+ $Xsession = $cmd;
+ last;
+ }
+ }
+ if (not defined $Xsession) {
+ die "$prog: Couldn't find suitable Xsession.\n";
+ }
+
+
+ if (!defined($ENV{HOME})) {
+ die "$prog: The HOME environment variable is not set.\n";
+ }
+
+ #
+ # Find socket constants. 'use Socket' is a perl5-ism, so we wrap it in an
+ # eval, and if it fails we try 'require "sys/socket.ph"'. If this fails,
+ # we just guess at the values. If you find perl moaning here, just
+ # hard-code the values of AF_INET and SOCK_STREAM. You can find these out
+ # for your platform by looking in /usr/include/sys/socket.h and related
+ # files.
+ #
+
+ chop($os = `uname`);
+ chop($osrev = `uname -r`);
+
+ eval 'use Socket';
+ if ($@) {
+ eval 'require "sys/socket.ph"';
+ if ($@) {
+ if (($os eq "SunOS") && ($osrev !~ /^4/)) {
+ $AF_INET = 2;
+ $SOCK_STREAM = 2;
+ } else {
+ $AF_INET = 2;
+ $SOCK_STREAM = 1;
+ }
+ } else {
+ $AF_INET = &AF_INET;
+ $SOCK_STREAM = &SOCK_STREAM;
+ }
+ } else {
+ $AF_INET = &AF_INET;
+ $SOCK_STREAM = &SOCK_STREAM;
+ }
+}
diff --git a/unix/vncserver/vncserver.man b/unix/vncserver/vncserver.man
new file mode 100644
index 0000000..f1017be
--- /dev/null
+++ b/unix/vncserver/vncserver.man
@@ -0,0 +1 @@
+.so man8/vncsession.8
diff --git a/unix/vncserver/vncserver.users b/unix/vncserver/vncserver.users
new file mode 100644
index 0000000..24875c8
--- /dev/null
+++ b/unix/vncserver/vncserver.users
@@ -0,0 +1,8 @@
+# TigerVNC User assignment
+#
+# This file assigns users to specific VNC display numbers.
+# The syntax is <display>=<username>. E.g.:
+#
+# :2=andrew
+# :3=lisa
+
diff --git a/unix/vncserver/vncserver@.service.in b/unix/vncserver/vncserver@.service.in
new file mode 100644
index 0000000..584ecf4
--- /dev/null
+++ b/unix/vncserver/vncserver@.service.in
@@ -0,0 +1,43 @@
+# The vncserver service unit file
+#
+# Quick HowTo:
+# 1. Add a user mapping to /etc/tigervnc/vncserver.users.
+# 2. Adjust the global or user configuration. See the
+# vncsession(8) manpage for details. (OPTIONAL)
+# 3. Run `systemctl enable vncserver@:<display>.service`
+# 4. Run `systemctl start vncserver@:<display>.service`
+#
+# DO NOT RUN THIS SERVICE if your local area network is
+# untrusted! For a secure way of using VNC, you should
+# limit connections to the local host and then tunnel from
+# the machine you want to view VNC on (host A) to the machine
+# whose VNC output you want to view (host B)
+#
+# [user@hostA ~]$ ssh -v -C -L 590N:localhost:590M hostB
+#
+# this will open a connection on port 590N of your hostA to hostB's port 590M
+# (in fact, it ssh-connects to hostB and then connects to localhost (on hostB).
+# See the ssh man page for details on port forwarding)
+#
+# You can then point a VNC client on hostA at vncdisplay N of localhost and with
+# the help of ssh, you end up seeing what hostB makes available on port 590M
+#
+# Use "nolisten=tcp" to prevent X connections to your VNC server via TCP.
+#
+# Use "localhost" to prevent remote VNC clients connecting except when
+# doing so through a secure tunnel. See the "-via" option in the
+# `man vncviewer' manual page.
+
+
+[Unit]
+Description=Remote desktop service (VNC)
+After=syslog.target network.target
+
+[Service]
+Type=forking
+ExecStart=@CMAKE_INSTALL_FULL_LIBEXECDIR@/vncsession-start %i
+PIDFile=/var/run/vncsession-%i.pid
+SELinuxContext=system_u:system_r:vnc_session_t:s0
+
+[Install]
+WantedBy=multi-user.target
diff --git a/unix/vncserver/vncsession-start.in b/unix/vncserver/vncsession-start.in
new file mode 100644
index 0000000..b20fcdd
--- /dev/null
+++ b/unix/vncserver/vncsession-start.in
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Copyright 2019 Pierre Ossman for Cendio AB
+#
+# 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.
+#
+
+USERSFILE="@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver.users"
+
+if [ $# -ne 1 ]; then
+ echo "Syntax:" >&2
+ echo " $0 <display>" >&2
+ exit 1
+fi
+
+if [ ! -f "${USERSFILE}" ]; then
+ echo "Users file ${USERSFILE} missing" >&2
+ exit 1
+fi
+
+DISPLAY="$1"
+
+USER=`grep "^${DISPLAY}=" "${USERSFILE}" 2>/dev/null | head -1 | cut -d = -f 2-`
+
+if [ -z "${USER}" ]; then
+ echo "No user configured for display ${DISPLAY}" >&2
+ exit 1
+fi
+
+exec "@CMAKE_INSTALL_FULL_SBINDIR@/vncsession" "${USER}" "${DISPLAY}"
diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c
new file mode 100644
index 0000000..21a40f6
--- /dev/null
+++ b/unix/vncserver/vncsession.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2018 Pierre Ossman for Cendio AB
+ *
+ * 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 <config.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <security/pam_appl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+extern char **environ;
+
+// PAM service name
+const char *SERVICE_NAME = "tigervnc";
+
+// Main script PID
+volatile static pid_t script = -1;
+
+// Daemon completion pipe
+int daemon_pipe_fd = -1;
+
+static int
+begin_daemon(void)
+{
+ int devnull, fds[2];
+ pid_t pid;
+
+ /* Pipe to report startup success */
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return -1;
+ }
+
+ /* First fork */
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid != 0) {
+ ssize_t len;
+ char buf[1];
+
+ close(fds[1]);
+
+ /* Wait for child to finish startup */
+ len = read(fds[0], buf, 1);
+ if (len != 1) {
+ fprintf(stderr, "Failure daemonizing\n");
+ _exit(EX_OSERR);
+ }
+
+ _exit(0);
+ }
+
+ close(fds[0]);
+ daemon_pipe_fd = fds[1];
+
+ /* Detach from terminal */
+ if (setsid() < 0) {
+ perror("setsid");
+ return -1;
+ }
+
+ /* Another fork required to fully detach */
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0)
+ _exit(0);
+
+ /* Send all stdio to /dev/null */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ fprintf(stderr, "Failed to open /dev/null: %s\n", strerror(errno));
+ return -1;
+ }
+ if ((dup2(devnull, 0) < 0) ||
+ (dup2(devnull, 1) < 0) ||
+ (dup2(devnull, 2) < 0)) {
+ perror("dup2");
+ return -1;
+ }
+ if (devnull > 2)
+ close(devnull);
+
+ /* Full control of access bits */
+ umask(0);
+
+ /* A safe working directory */
+ if (chdir("/") < 0) {
+ perror("chdir");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+finish_daemon(void)
+{
+ write(daemon_pipe_fd, "+", 1);
+ close(daemon_pipe_fd);
+ daemon_pipe_fd = -1;
+}
+
+static void
+sighandler(int sig)
+{
+ if (script > 0) {
+ kill(script, SIGTERM);
+ }
+}
+
+static void
+setup_signals(void)
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sighandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGQUIT, &act, NULL);
+ sigaction(SIGPIPE, &act, NULL);
+}
+
+static int
+conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ /* Opening a session should not require a conversation */
+ return PAM_CONV_ERR;
+}
+
+static pam_handle_t *
+run_pam(int *pamret, const char *username, const char *display)
+{
+ pam_handle_t *pamh;
+
+ /* Say hello to PAM */
+ struct pam_conv pconv;
+ pconv.conv = conv;
+ pconv.appdata_ptr = NULL;
+ *pamret = pam_start(SERVICE_NAME, username, &pconv, &pamh);
+ if (*pamret != PAM_SUCCESS) {
+ /* pam_strerror requires a pamh argument, but if pam_start
+ fails, pamh is invalid. In practice, at least the Linux
+ implementation of pam_strerror does not use the pamh
+ argument, but let's take care - avoid pam_strerror here. */
+ syslog(LOG_CRIT, "pam_start failed: %d", *pamret);
+ return NULL;
+ }
+
+ /* ConsoleKit and systemd (and possibly others) uses this to
+ determine if the session is local or not. It needs to be set to
+ something that can't be interpreted as localhost. We don't know
+ what the client's address is though, and that might change on
+ reconnects. We also don't want to set it to some text string as
+ that results in a DNS lookup with e.g. libaudit. Let's use a
+ fake IPv4 address from the documentation range. */
+ /* FIXME: This might throw an error on a IPv6-only host */
+ *pamret = pam_set_item(pamh, PAM_RHOST, "203.0.113.20");
+ if (*pamret != PAM_SUCCESS) {
+ syslog(LOG_CRIT, "pam_set_item(PAM_RHOST) failed: %d (%s)",
+ *pamret, pam_strerror(pamh, *pamret));
+ return pamh;
+ }
+
+#ifdef PAM_XDISPLAY
+ /* Let PAM modules use this to tag the session as a graphical one */
+ *pamret = pam_set_item(pamh, PAM_XDISPLAY, display);
+ /* Note: PAM_XDISPLAY is only supported by modern versions of PAM */
+ if (*pamret != PAM_BAD_ITEM && *pamret != PAM_SUCCESS) {
+ syslog(LOG_CRIT, "pam_set_item(PAM_XDISPLAY) failed: %d (%s)",
+ *pamret, pam_strerror(pamh, *pamret));
+ return pamh;
+ }
+#endif
+
+ /* Open session */
+ *pamret = pam_open_session(pamh, PAM_SILENT);
+ if (*pamret != PAM_SUCCESS) {
+ syslog(LOG_CRIT, "pam_open_session failed: %d (%s)",
+ *pamret, pam_strerror(pamh, *pamret));
+ return pamh;
+ }
+
+ return pamh;
+}
+
+static int
+stop_pam(pam_handle_t * pamh, int pamret)
+{
+ /* Close session */
+ if (pamret == PAM_SUCCESS) {
+ pamret = pam_close_session(pamh, PAM_SILENT);
+ if (pamret != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_close_session failed: %d (%s)",
+ pamret, pam_strerror(pamh, pamret));
+ }
+ }
+
+ /* If PAM was OK and we are running on a SELinux system, new
+ processes images will be executed in the root context. */
+
+ /* Say goodbye */
+ pamret = pam_end(pamh, pamret);
+ if (pamret != PAM_SUCCESS) {
+ /* avoid pam_strerror - we have no pamh. */
+ syslog(LOG_ERR, "pam_end failed: %d", pamret);
+ return EX_OSERR;
+ }
+ return pamret;
+}
+
+static char **
+prepare_environ(pam_handle_t * pamh)
+{
+ char **pam_env, **child_env, **entry;
+ int orig_count, pam_count;
+
+ /* This function merges the normal environment with PAM's changes */
+
+ pam_env = pam_getenvlist(pamh);
+ if (pam_env == NULL)
+ return NULL;
+
+ /*
+ * Worst case scenario is that PAM only adds variables, so allocate
+ * based on that assumption.
+ */
+ orig_count = 0;
+ for (entry = environ; *entry != NULL; entry++)
+ orig_count++;
+ pam_count = 0;
+ for (entry = pam_env; *entry != NULL; entry++)
+ pam_count++;
+
+ child_env = calloc(orig_count + pam_count + 1, sizeof(char *));
+ if (child_env == NULL)
+ return NULL;
+
+ memcpy(child_env, environ, sizeof(char *) * orig_count);
+ for (entry = child_env; *entry != NULL; entry++) {
+ *entry = strdup(*entry);
+ if (*entry == NULL) // FIXME: cleanup
+ return NULL;
+ }
+
+ for (entry = pam_env; *entry != NULL; entry++) {
+ size_t varlen;
+ char **orig_entry;
+
+ varlen = strcspn(*entry, "=") + 1;
+
+ /* Check for overwrite */
+ for (orig_entry = child_env; *orig_entry != NULL; orig_entry++) {
+ if (strncmp(*entry, *orig_entry, varlen) != 0)
+ continue;
+
+ free(*orig_entry);
+ *orig_entry = *entry;
+ break;
+ }
+
+ /* New variable? */
+ if (*orig_entry == NULL) {
+ /*
+ * orig_entry will be pointing at the terminating entry,
+ * so we can just tack it on here. The new NULL was already
+ * prepared by calloc().
+ */
+ *orig_entry = *entry;
+ }
+ }
+
+ return child_env;
+}
+
+static void
+switch_user(const char *username, uid_t uid, gid_t gid)
+{
+ // We must change group stuff first, because only root can do that.
+ if (setgid(gid) < 0) {
+ perror(": setgid");
+ _exit(EX_OSERR);
+ }
+
+ // Supplementary groups.
+ if (initgroups(username, gid) < 0) {
+ perror("initgroups");
+ _exit(EX_OSERR);
+ }
+
+ // Set euid, ruid and suid
+ if (setuid(uid) < 0) {
+ perror("setuid");
+ _exit(EX_OSERR);
+ }
+}
+
+static void
+redir_stdio(const char *homedir, const char *display)
+{
+ int fd;
+ char hostname[HOST_NAME_MAX+1];
+ char logfile[PATH_MAX];
+
+ fd = open("/dev/null", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ _exit(EX_OSERR);
+ }
+ if (dup2(fd, 0) == -1) {
+ perror("dup2");
+ _exit(EX_OSERR);
+ }
+ close(fd);
+
+ snprintf(logfile, sizeof(logfile), "%s/.vnc", homedir);
+ if (mkdir(logfile, 0755) == -1) {
+ if (errno != EEXIST) {
+ perror("mkdir");
+ _exit(EX_OSERR);
+ }
+ }
+
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ perror("gethostname");
+ _exit(EX_OSERR);
+ }
+
+ snprintf(logfile, sizeof(logfile), "%s/.vnc/%s%s.log",
+ homedir, hostname, display);
+ fd = open(logfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ if (fd == -1) {
+ perror("open");
+ _exit(EX_OSERR);
+ }
+ if ((dup2(fd, 1) == -1) || (dup2(fd, 2) == -1)) {
+ perror("dup2");
+ _exit(EX_OSERR);
+ }
+ close(fd);
+}
+
+static void
+close_fds(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ dir = opendir("/proc/self/fd");
+ if (dir == NULL) {
+ perror("opendir");
+ _exit(EX_OSERR);
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ int fd;
+ fd = atoi(entry->d_name);
+ if (fd < 3)
+ continue;
+ close(fd);
+ }
+
+ closedir(dir);
+}
+
+static pid_t
+run_script(const char *username, const char *display, char **envp)
+{
+ struct passwd *pwent;
+ pid_t pid;
+ const char *child_argv[3];
+
+ pwent = getpwnam(username);
+ if (pwent == NULL) {
+ syslog(LOG_CRIT, "getpwnam: %s", strerror(errno));
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ syslog(LOG_CRIT, "fork: %s", strerror(errno));
+ return pid;
+ }
+
+ /* two processes now */
+
+ if (pid > 0)
+ return pid;
+
+ /* child */
+
+ switch_user(pwent->pw_name, pwent->pw_uid, pwent->pw_gid);
+
+ close_fds();
+
+ redir_stdio(pwent->pw_dir, display);
+
+ // execvpe() is not POSIX and is missing from older glibc
+ // First clear out everything
+ while ((environ != NULL) && (*environ != NULL)) {
+ char *var, *eq;
+ var = strdup(*environ);
+ eq = strchr(var, '=');
+ if (eq)
+ *eq = '\0';
+ unsetenv(var);
+ free(var);
+ }
+
+ // Then copy over the desired environment
+ for (; *envp != NULL; envp++)
+ putenv(*envp);
+
+ // Set up some basic environment for the script
+ setenv("HOME", pwent->pw_dir, 1);
+ setenv("SHELL", pwent->pw_shell, 1);
+ setenv("LOGNAME", pwent->pw_name, 1);
+ setenv("USER", pwent->pw_name, 1);
+ setenv("USERNAME", pwent->pw_name, 1);
+
+ child_argv[0] = CMAKE_INSTALL_FULL_LIBEXECDIR "/vncserver";
+ child_argv[1] = display;
+ child_argv[2] = NULL;
+
+ execvp(child_argv[0], (char*const*)child_argv);
+
+ // execvp failed
+ perror("execvp");
+
+ _exit(EX_OSERR);
+}
+
+int
+main(int argc, char **argv)
+{
+ char pid_file[PATH_MAX];
+ FILE *f;
+
+ const char *username, *display;
+
+ if ((argc != 3) || (argv[2][0] != ':')) {
+ fprintf(stderr, "Syntax:\n");
+ fprintf(stderr, " %s <username> <display>\n", argv[0]);
+ return EX_USAGE;
+ }
+
+ username = argv[1];
+ display = argv[2];
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "This program needs to be run as root!\n");
+ return EX_USAGE;
+ }
+
+ if (getpwnam(username) == NULL) {
+ if (errno == 0)
+ fprintf(stderr, "User \"%s\" does not exist\n", username);
+ else
+ fprintf(stderr, "Cannot look up user \"%s\": %s\n",
+ username, strerror(errno));
+ return EX_OSERR;
+ }
+
+ if (begin_daemon() == -1)
+ return EX_OSERR;
+
+ openlog("vncsession", LOG_PID, LOG_AUTH);
+
+ /* Indicate that this is a graphical user session. We need to do
+ this here before PAM as pam_systemd.so looks at these. */
+ if ((putenv("XDG_SESSION_CLASS=user") < 0) ||
+ (putenv("XDG_SESSION_TYPE=x11") < 0)) {
+ syslog(LOG_CRIT, "putenv: %s", strerror(errno));
+ return EX_OSERR;
+ }
+
+ /* Init PAM */
+ int pamret;
+ pam_handle_t *pamh = run_pam(&pamret, username, display);
+ if (!pamh) {
+ return EX_OSERR;
+ }
+ if (pamret != PAM_SUCCESS) {
+ stop_pam(pamh, pamret);
+ return EX_OSERR;
+ }
+
+ char **child_env;
+ child_env = prepare_environ(pamh);
+ if (child_env == NULL) {
+ syslog(LOG_CRIT, "Failure creating child process environment");
+ stop_pam(pamh, pamret);
+ return EX_OSERR;
+ }
+
+ setup_signals();
+
+ script = run_script(username, display, child_env);
+ if (script == -1) {
+ syslog(LOG_CRIT, "Failure starting vncserver script");
+ stop_pam(pamh, pamret);
+ return EX_OSERR;
+ }
+
+ snprintf(pid_file, sizeof(pid_file),
+ "/var/run/vncsession-%s.pid", display);
+ f = fopen(pid_file, "w");
+ if (f == NULL) {
+ syslog(LOG_ERR, "Failure creating pid file \"%s\": %s",
+ pid_file, strerror(errno));
+ } else {
+ fprintf(f, "%ld\n", (long)getpid());
+ fclose(f);
+ }
+
+ finish_daemon();
+
+ while (1) {
+ int status;
+ pid_t gotpid = waitpid(script, &status, 0);
+ if (gotpid < 0) {
+ if (errno != EINTR) {
+ syslog(LOG_CRIT, "waitpid: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ syslog(LOG_WARNING,
+ "vncsession: vncserver exited with status=%d",
+ WEXITSTATUS(status));
+ }
+ break;
+ }
+ else if (WIFSIGNALED(status)) {
+ syslog(LOG_WARNING,
+ "vncsession: vncserver was terminated by signal %d",
+ WTERMSIG(status));
+ break;
+ }
+ }
+
+ unlink(pid_file);
+
+ stop_pam(pamh, pamret);
+
+ return 0;
+}
diff --git a/unix/vncserver/vncsession.man b/unix/vncserver/vncsession.man
new file mode 100644
index 0000000..2138209
--- /dev/null
+++ b/unix/vncserver/vncsession.man
@@ -0,0 +1,75 @@
+.TH vncsession 8 "" "TigerVNC" "Virtual Network Computing"
+.SH NAME
+vncsession \- start a VNC server
+.SH SYNOPSIS
+.B vncsession
+.RI < username >
+.RI <: display# >
+.SH DESCRIPTION
+.B vncsession
+is used to start a VNC (Virtual Network Computing) desktop.
+.B vncsession
+performs all the necessary steps to create a new user session, run Xvnc with
+appropriate options and starts a window manager on the VNC desktop.
+
+.B vncsession
+is rarely called directly and is normally started by the system service
+manager.
+
+.SH FILES
+Several VNC-related files are found in the directory $HOME/.vnc:
+.TP
+/etc/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 /etc/tigervnc/vncserver-config-mandatory. None are required to exist.
+.TP
+/etc/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
+/etc/tigervnc/vncserver-config-mandatory. The overall configuration file load
+order is: /etc/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then
+this file. None are required to exist.
+.TP
+$HOME/.vnc/config
+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
+the argument with an equal sign, for example: "geometry=2000x1200" or
+"securitytypes=vncauth,tlsvnc". Options without an argument are simply listed
+as a single word, for example: "localhost" or "alwaysshared".
+
+The special option
+.B session
+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
+The VNC password file.
+.TP
+$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
+The log file for Xvnc and the session.
+
+.SH SEE ALSO
+.BR vncviewer (1),
+.BR vncpasswd (1),
+.BR vncconfig (1),
+.BR Xvnc (1)
+.br
+https://www.tigervnc.org
+
+.SH AUTHOR
+Tristan Richardson, RealVNC Ltd., D. R. Commander and others.
+
+VNC was originally developed by the RealVNC team while at Olivetti
+Research Ltd / AT&T Laboratories Cambridge. TightVNC additions were
+implemented by Constantin Kaplinsky. Many other people have since
+participated in development, testing and support. This manual is part
+of the TigerVNC software suite.
diff --git a/unix/x0vncserver/CMakeLists.txt b/unix/x0vncserver/CMakeLists.txt
index 8beade7..af82415 100644
--- a/unix/x0vncserver/CMakeLists.txt
+++ b/unix/x0vncserver/CMakeLists.txt
@@ -52,5 +52,5 @@ endif()
target_link_libraries(x0vncserver ${X11_LIBRARIES})
-install(TARGETS x0vncserver DESTINATION ${BIN_DIR})
-install(FILES x0vncserver.man DESTINATION ${MAN_DIR}/man1 RENAME x0vncserver.1)
+install(TARGETS x0vncserver DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
+install(FILES x0vncserver.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1 RENAME x0vncserver.1)
diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index 9c8a889..9559179 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -18,9 +18,9 @@ that the VNC server display number will be the same as the X server display
number, which means you can use eg. snoopy:2 to refer to display 2 on machine
"snoopy" in both the X world and the VNC world.
-The best way of starting \fBXvnc\fP is via the \fBvncserver\fP script. This
-sets up the environment appropriately and runs some X applications to get you
-going. See the manual page for \fBvncserver\fP(1) for more information.
+The best way of starting \fBXvnc\fP is via \fBvncsession\fP. This sets up the
+environment appropriately and starts a desktop environment. See the manual
+page for \fBvncsession\fP(8) for more information.
.SH OPTIONS
.B Xvnc
@@ -383,8 +383,8 @@ created automatically the next time he connects.
.SH SEE ALSO
.BR vncconfig (1),
.BR vncpasswd (1),
-.BR vncserver (1),
.BR vncviewer (1),
+.BR vncsession (8),
.BR Xserver (1),
.BR inetd (1)
.br
diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt
index 3c18646..7e25d45 100644
--- a/vncviewer/CMakeLists.txt
+++ b/vncviewer/CMakeLists.txt
@@ -60,9 +60,9 @@ if(APPLE)
target_link_libraries(vncviewer "-framework IOKit")
endif()
-install(TARGETS vncviewer DESTINATION ${BIN_DIR})
+install(TARGETS vncviewer DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
if(UNIX)
- install(FILES vncviewer.man DESTINATION ${MAN_DIR}/man1 RENAME vncviewer.1)
+ install(FILES vncviewer.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1 RENAME vncviewer.1)
configure_file(vncviewer.desktop.in.in vncviewer.desktop.in)
find_program(INTLTOOL_MERGE_EXECUTABLE intltool-merge)
@@ -91,10 +91,10 @@ if(UNIX)
)
endif()
add_custom_target(desktop ALL DEPENDS vncviewer.desktop)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/vncviewer.desktop DESTINATION ${DATA_DIR}/applications)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/vncviewer.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications)
foreach(res 16 22 24 32 48)
- install(FILES ../media/icons/tigervnc_${res}.png DESTINATION ${DATA_DIR}/icons/hicolor/${res}x${res}/apps RENAME tigervnc.png)
+ install(FILES ../media/icons/tigervnc_${res}.png DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/${res}x${res}/apps RENAME tigervnc.png)
endforeach()
- install(FILES ../media/icons/tigervnc.svg DESTINATION ${DATA_DIR}/icons/hicolor/scalable/apps)
+ install(FILES ../media/icons/tigervnc.svg DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps)
endif()
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index 4a8370b..ae4cb6f 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -227,7 +227,7 @@ static void init_fltk()
bool exists;
sprintf(icon_path, "%s/icons/hicolor/%dx%d/apps/tigervnc.png",
- DATA_DIR, icon_sizes[i], icon_sizes[i]);
+ CMAKE_INSTALL_FULL_DATADIR, icon_sizes[i], icon_sizes[i]);
#ifndef WIN32
struct stat st;
@@ -505,7 +505,7 @@ int main(int argc, char** argv)
argv0 = argv[0];
setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE_NAME, LOCALE_DIR);
+ bindtextdomain(PACKAGE_NAME, CMAKE_INSTALL_FULL_LOCALEDIR);
textdomain(PACKAGE_NAME);
rfb::SecurityClient::setDefaults();
diff --git a/vncviewer/vncviewer.desktop.in.in b/vncviewer/vncviewer.desktop.in.in
index d775dde..9d658e4 100644
--- a/vncviewer/vncviewer.desktop.in.in
+++ b/vncviewer/vncviewer.desktop.in.in
@@ -2,7 +2,7 @@
Name=TigerVNC Viewer
GenericName=Remote Desktop Viewer
Comment=Connect to VNC server and display remote desktop
-Exec=@BIN_DIR@/vncviewer
+Exec=@CMAKE_INSTALL_FULL_BINDIR@/vncviewer
Icon=tigervnc
Terminal=false
Type=Application
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index f93e096..a8d8c77 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -327,7 +327,7 @@ Default certificate revocation list.
.BR Xvnc (1),
.BR vncpasswd (1),
.BR vncconfig (1),
-.BR vncserver (1)
+.BR vncsession (8)
.br
https://www.tigervnc.org