From 8f09de712b53e54d15d2bd5367c10a61c57cda23 Mon Sep 17 00:00:00 2001 From: Jan Grulich 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 #include #include -#ifdef HAVE_PAM +#if !defined(WIN32) && !defined(__APPLE__) #include #endif -#ifdef BUILD_WIN +#ifdef WIN32 #include #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 #include #include -#ifdef HAVE_PAM #include -#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 #endif -#ifndef HAVE_PAM -#error "This source should not be compiled when PAM is unsupported" -#endif #include #include 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 -#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 @@ +## 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 () { + 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 = ) { + 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 \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 =. 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@:.service` +# 4. Run `systemctl start vncserver@:.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 " >&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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 \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