diff --git a/.gitignore b/.gitignore
index bcdfabc..473d203 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/tigervnc-1.9.0.tar.gz
+SOURCES/tigervnc-1.10.1.tar.gz
diff --git a/.tigervnc.metadata b/.tigervnc.metadata
index 60dae98..957f8a1 100644
--- a/.tigervnc.metadata
+++ b/.tigervnc.metadata
@@ -1 +1 @@
-c56656c596fb863bb2c4b67fb62b4165011d181f SOURCES/tigervnc-1.9.0.tar.gz
+34efc6e2e67be672dca38c10ce064bcb08adee9f SOURCES/tigervnc-1.10.1.tar.gz
diff --git a/SOURCES/0001-xserver-add-no-op-input-thread-init-function.patch b/SOURCES/0001-xserver-add-no-op-input-thread-init-function.patch
new file mode 100644
index 0000000..b67127b
--- /dev/null
+++ b/SOURCES/0001-xserver-add-no-op-input-thread-init-function.patch
@@ -0,0 +1,34 @@
+From 920d9c4d6562ecabf79497bc901d50522d4bc661 Mon Sep 17 00:00:00 2001
+From: Linus Heckemann <git@sphalerite.org>
+Date: Sat, 1 Feb 2020 11:08:26 +0100
+Subject: [PATCH] xserver: add no-op input thread init function
+
+This allows Xvnc to build with xorg-server 1.20.7, which requires OS
+layers to implement a ddxInputThreadInit function when configured with
+--enable-input-thread (the default).
+
+relevant xorg-server commit: e3f26605d85d987da434640f52646d728f1fe919
+---
+ unix/xserver/hw/vnc/Input.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c
+index 534e435e..b342d4d6 100644
+--- a/unix/xserver/hw/vnc/Input.c
++++ b/unix/xserver/hw/vnc/Input.c
+@@ -711,3 +711,12 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
+ 	 */
+ 	mieqProcessInputEvents();
+ }
++
++#if INPUTTHREAD
++/** This function is called in Xserver/os/inputthread.c when starting
++    the input thread. */
++void
++ddxInputThreadInit(void)
++{
++}
++#endif
+-- 
+2.24.1
+
diff --git a/SOURCES/tigervnc-1.3.1-do-not-die-when-port-is-already-taken.patch b/SOURCES/tigervnc-1.3.1-do-not-die-when-port-is-already-taken.patch
deleted file mode 100644
index 3623b14..0000000
--- a/SOURCES/tigervnc-1.3.1-do-not-die-when-port-is-already-taken.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/unix/vncserver b/unix/vncserver
-index a6c890f..687ef72 100755
---- a/unix/vncserver
-+++ b/unix/vncserver
-@@ -208,7 +208,8 @@ if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
-     $displayNumber = $1;
-     shift(@ARGV);
-     if (!&CheckDisplayNumber($displayNumber)) {
--	die "A VNC server is already running as :$displayNumber\n";
-+        warn "A VNC server is already running as :$displayNumber\n";
-+        $displayNumber = &GetDisplayNumber();
-     }
- } elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/) && ($ARGV[0] !~ /^\+/)) {
-     &Usage();
diff --git a/SOURCES/tigervnc-covscan.patch b/SOURCES/tigervnc-covscan.patch
deleted file mode 100644
index 803f71a..0000000
--- a/SOURCES/tigervnc-covscan.patch
+++ /dev/null
@@ -1,312 +0,0 @@
-diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
-index 51d77c76..9e277cbb 100644
---- a/common/network/TcpSocket.cxx
-+++ b/common/network/TcpSocket.cxx
-@@ -736,7 +736,7 @@ char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
-                 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
-     strcat(buffer, "]");
-     addr.buf = rfb::strDup(buffer);
--  } else if (p.address.u.sa.sa_family == AF_UNSPEC)
-+  } else
-     addr.buf = rfb::strDup("");
- 
-   char action;
-diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
-index e1a31f78..d268202b 100644
---- a/common/rfb/CSecurityTLS.cxx
-+++ b/common/rfb/CSecurityTLS.cxx
-@@ -95,9 +95,9 @@ void CSecurityTLS::setDefaults()
-   delete [] homeDir;
- 
-  if (!fileexists(caDefault.buf))
--   X509CA.setDefaultStr(strdup(caDefault.buf));
-+   X509CA.setDefaultStr(caDefault.buf);
-  if (!fileexists(crlDefault.buf))
--   X509CRL.setDefaultStr(strdup(crlDefault.buf));
-+   X509CRL.setDefaultStr(crlDefault.buf);
- }
- 
- void CSecurityTLS::shutdown(bool needbye)
-diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
-index 6d48b65c..6f72432a 100644
---- a/common/rfb/SSecurityPlain.cxx
-+++ b/common/rfb/SSecurityPlain.cxx
-@@ -41,7 +41,7 @@ StringParameter PasswordValidator::plainUsers
- 
- bool PasswordValidator::validUser(const char* username)
- {
--  CharArray users(strDup(plainUsers.getValueStr())), user;
-+  CharArray users(plainUsers.getValueStr()), user;
- 
-   while (users.buf) {
-     strSplit(users.buf, ',', &user.buf, &users.buf);
-diff --git a/unix/tx/TXWindow.cxx b/unix/tx/TXWindow.cxx
-index a6819179..6129840e 100644
---- a/unix/tx/TXWindow.cxx
-+++ b/unix/tx/TXWindow.cxx
-@@ -24,6 +24,7 @@
- #include <list>
- #include <stdio.h>
- #include <stdlib.h>
-+#include <vector>
- #include <rfb/util.h>
- 
- std::list<TXWindow*> windows;
-@@ -132,20 +133,20 @@ TXGlobalEventHandler* TXWindow::setGlobalEventHandler(TXGlobalEventHandler* h)
- 
- void TXWindow::getColours(Display* dpy, XColor* cols, int nCols)
- {
--  bool* got = new bool[nCols];
-+  std::vector<bool> got;
-+
-   bool failed = false;
-   int i;
-   for (i = 0; i < nCols; i++) {
-     if (XAllocColor(dpy, cmap, &cols[i])) {
--      got[i] = true;
-+      got.push_back(true);
-     } else {
--      got[i] = false;
-+      got.push_back(false);
-       failed = true;
-     }
-   }
- 
-   if (!failed) {
--    delete [] got;
-     return;
-   }
- 
-@@ -168,12 +169,13 @@ void TXWindow::getColours(Display* dpy, XColor* cols, int nCols)
-   int cmapSize = DisplayCells(dpy,DefaultScreen(dpy));
- 
-   XColor* cm = new XColor[cmapSize];
--  bool* shared = new bool[cmapSize];
--  bool* usedAsNearest = new bool[cmapSize];
-+  std::vector<bool> shared;
-+  std::vector<bool> usedAsNearest;
- 
-   for (i = 0; i < cmapSize; i++) {
-     cm[i].pixel = i;
--    shared[i] = usedAsNearest[i] = false;
-+    shared.push_back(false);
-+    usedAsNearest.push_back(false);
-   }
- 
-   XQueryColors(dpy, cmap, cm, cmapSize);
-diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx
-index 8bd4e48e..3055223e 100644
---- a/unix/vncpasswd/vncpasswd.cxx
-+++ b/unix/vncpasswd/vncpasswd.cxx
-@@ -134,7 +134,7 @@ int main(int argc, char** argv)
-     } else if (argv[i][0] == '-') {
-       usage();
-     } else if (!fname) {
--      fname = argv[i];
-+      fname = strDup(argv[i]);
-     } else {
-       usage();
-     }
-@@ -165,24 +165,37 @@ int main(int argc, char** argv)
-     FILE* fp = fopen(fname,"w");
-     if (!fp) {
-       fprintf(stderr,"Couldn't open %s for writing\n",fname);
-+      delete [] fname;
-+      delete obfuscated;
-+      delete obfuscatedReadOnly;
-       exit(1);
-     }
-     chmod(fname, S_IRUSR|S_IWUSR);
- 
-     if (fwrite(obfuscated->buf, obfuscated->length, 1, fp) != 1) {
-       fprintf(stderr,"Writing to %s failed\n",fname);
-+      delete [] fname;
-+      delete obfuscated;
-+      delete obfuscatedReadOnly;
-       exit(1);
-     }
- 
-+    delete obfuscated;
-+
-     if (obfuscatedReadOnly) {
-       if (fwrite(obfuscatedReadOnly->buf, obfuscatedReadOnly->length, 1, fp) != 1) {
-         fprintf(stderr,"Writing to %s failed\n",fname);
-+        delete [] fname;
-+        delete obfuscatedReadOnly;
-         exit(1);
-       }
-     }
- 
-     fclose(fp);
- 
-+    delete [] fname;
-+    delete obfuscatedReadOnly;
-+
-     return 0;
-   }
- }
-diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
-index d6f6b742..7ca71d94 100644
---- a/unix/xserver/hw/vnc/vncExtInit.cc
-+++ b/unix/xserver/hw/vnc/vncExtInit.cc
-@@ -184,7 +184,7 @@ void vncExtensionInit(void)
-             listeners.push_back(new network::TcpListener(vncInetdSock));
-             vlog.info("inetd wait");
-           }
--        } else if (rfbunixpath.getValueStr()[0] != '\0') {
-+        } else if (((const char*)rfbunixpath)[0] != '\0') {
-           char path[PATH_MAX];
-           int mode = (int)rfbunixmode;
- 
-@@ -192,7 +192,7 @@ void vncExtensionInit(void)
-             strncpy(path, rfbunixpath, sizeof(path));
-           else
-             snprintf(path, sizeof(path), "%s.%d",
--                     rfbunixpath.getValueStr(), scr);
-+                     (const char*)rfbunixpath, scr);
-           path[sizeof(path)-1] = '\0';
- 
-           listeners.push_back(new network::UnixListener(path, mode));
-diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
-index 51dfd9c6..4f3538d4 100644
---- a/unix/xserver/hw/vnc/vncSelection.c
-+++ b/unix/xserver/hw/vnc/vncSelection.c
-@@ -105,7 +105,7 @@ void vncClientCutText(const char* str, int len)
-       LOG_ERROR("Could not set PRIMARY selection");
-   }
- 
--  vncOwnSelection(xaCLIPBOARD);
-+  rc = vncOwnSelection(xaCLIPBOARD);
-   if (rc != Success)
-     LOG_ERROR("Could not set CLIPBOARD selection");
- }
-diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
-index 3b4d2f31..c845ebc4 100644
---- a/unix/xserver/hw/vnc/xvnc.c
-+++ b/unix/xserver/hw/vnc/xvnc.c
-@@ -766,10 +766,13 @@ vfbUninstallColormap(ColormapPtr pmap)
- 	    curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
- 						   RT_COLORMAP);
- #else
--	    dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
--				    RT_COLORMAP, serverClient, DixUnknownAccess);
-+	    int rc =  dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
-+					      RT_COLORMAP, serverClient, DixUnknownAccess);
-+	    if (rc != Success)
-+		ErrorF("Failed to uninstall color map\n");
-+	    else
- #endif
--	    (*pmap->pScreen->InstallColormap)(curpmap);
-+		(*pmap->pScreen->InstallColormap)(curpmap);
- 	}
-     }
- }
-diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
-index d070b648..1843485a 100644
---- a/vncviewer/DesktopWindow.cxx
-+++ b/vncviewer/DesktopWindow.cxx
-@@ -103,12 +103,12 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
-   int geom_x = 0, geom_y = 0;
-   if (strcmp(geometry, "") != 0) {
-     int matched;
--    matched = sscanf(geometry.getValueStr(), "+%d+%d", &geom_x, &geom_y);
-+    matched = sscanf((const char*)geometry, "+%d+%d", &geom_x, &geom_y);
-     if (matched == 2) {
-       force_position(1);
-     } else {
-       int geom_w, geom_h;
--      matched = sscanf(geometry.getValueStr(), "%dx%d+%d+%d", &geom_w, &geom_h, &geom_x, &geom_y);
-+      matched = sscanf((const char*)geometry, "%dx%d+%d+%d", &geom_w, &geom_h, &geom_x, &geom_y);
-       switch (matched) {
-       case 4:
-         force_position(1);
-diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
-index b018c95b..62b5d9c5 100644
---- a/vncviewer/OptionsDialog.cxx
-+++ b/vncviewer/OptionsDialog.cxx
-@@ -282,7 +282,7 @@ void OptionsDialog::loadOptions(void)
-   /* Screen */
-   int width, height;
- 
--  if (sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) != 2) {
-+  if (sscanf((const char*)desktopSize, "%dx%d", &width, &height) != 2) {
-     desktopSizeCheckbox->value(false);
-     desktopWidthInput->value("1024");
-     desktopHeightInput->value("768");
-diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx
-index de67f87b..fec17896 100644
---- a/vncviewer/ServerDialog.cxx
-+++ b/vncviewer/ServerDialog.cxx
-@@ -150,7 +150,7 @@ void ServerDialog::handleLoad(Fl_Widget *widget, void *data)
-     return;
-   }
-   
--  const char* filename = strdup(file_chooser->value());
-+  const char* filename = file_chooser->value();
- 
-   try {
-     dialog->serverName->value(loadViewerParameters(filename));
-@@ -165,8 +165,8 @@ void ServerDialog::handleLoad(Fl_Widget *widget, void *data)
- void ServerDialog::handleSaveAs(Fl_Widget *widget, void *data)
- { 
-   ServerDialog *dialog = (ServerDialog*)data;
--  const char* servername = strdup(dialog->serverName->value());
--  char* filename;
-+  const char* servername = dialog->serverName->value();
-+  const char* filename;
- 
-   Fl_File_Chooser* file_chooser = new Fl_File_Chooser("", _("TigerVNC configuration (*.tigervnc)"), 
- 						      2, _("Save the TigerVNC configuration to file"));
-@@ -187,7 +187,7 @@ void ServerDialog::handleSaveAs(Fl_Widget *widget, void *data)
-       return;
-     }
-     
--    filename = strdup(file_chooser->value());
-+    filename = file_chooser->value();
-     
-     FILE* f = fopen(filename, "r");
-     if (f) {
-@@ -235,7 +235,7 @@ void ServerDialog::handleCancel(Fl_Widget *widget, void *data)
- void ServerDialog::handleConnect(Fl_Widget *widget, void *data)
- {
-   ServerDialog *dialog = (ServerDialog*)data;
--  const char* servername = strdup(dialog->serverName->value());
-+  const char* servername = dialog->serverName->value();
- 
-   dialog->hide();
-   
-diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
-index 51cce3d7..94cc1b05 100644
---- a/vncviewer/parameters.cxx
-+++ b/vncviewer/parameters.cxx
-@@ -499,6 +499,7 @@ void saveViewerParameters(const char *filename, const char *servername) {
-     }
- 
-     snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
-+    free(homeDir);
-   } else {
-     snprintf(filepath, sizeof(filepath), "%s", filename);
-   }
-@@ -555,6 +556,7 @@ char* loadViewerParameters(const char *filename) {
-                         "can't obtain home directory path."));
- 
-     snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
-+    free(homeDir);
-   } else {
-     snprintf(filepath, sizeof(filepath), "%s", filename);
-   }
-diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
-index f076565f..a9d4dfea 100644
---- a/vncviewer/vncviewer.cxx
-+++ b/vncviewer/vncviewer.cxx
-@@ -470,9 +470,9 @@ static int mktunnel()
-   int localPort = findFreeTcpPort();
-   int remotePort;
- 
--  gatewayHost = strDup(via.getValueStr());
-   if (interpretViaParam(remoteHost, &remotePort, localPort) != 0)
-     return 1;
-+  gatewayHost = (const char*)via;
-   createTunnel(gatewayHost, remoteHost, remotePort, localPort);
- 
-   return 0;
diff --git a/SOURCES/tigervnc-getmaster.patch b/SOURCES/tigervnc-getmaster.patch
index 23c3d58..6ef99b4 100644
--- a/SOURCES/tigervnc-getmaster.patch
+++ b/SOURCES/tigervnc-getmaster.patch
@@ -1,9 +1,9 @@
 diff --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c
-index a9bd11d..7b54b43 100644
+index f84a6e4..4eac939 100644
 --- a/unix/xserver/hw/vnc/InputXKB.c
 +++ b/unix/xserver/hw/vnc/InputXKB.c
-@@ -214,10 +214,7 @@ void vncPrepareInputDevices(void)
-
+@@ -226,10 +226,7 @@ void vncPrepareInputDevices(void)
+ 
  unsigned vncGetKeyboardState(void)
  {
 -	DeviceIntPtr master;
@@ -12,75 +12,75 @@ index a9bd11d..7b54b43 100644
 -	return XkbStateFieldFromRec(&master->key->xkbInfo->state);
 +	return XkbStateFieldFromRec(&vncKeyboardDev->master->key->xkbInfo->state);
  }
-
+ 
  unsigned vncGetLevelThreeMask(void)
-@@ -238,7 +235,7 @@ unsigned vncGetLevelThreeMask(void)
+@@ -250,7 +247,7 @@ unsigned vncGetLevelThreeMask(void)
  			return 0;
  	}
-
+ 
 -	xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 +	xkb = vncKeyboardDev->master->key->xkbInfo->desc;
-
+ 
  	act = XkbKeyActionPtr(xkb, keycode, state);
  	if (act == NULL)
-@@ -263,7 +260,7 @@ KeyCode vncPressShift(void)
+@@ -275,7 +272,7 @@ KeyCode vncPressShift(void)
  	if (state & ShiftMask)
  		return 0;
-
+ 
 -	xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 +	xkb = vncKeyboardDev->master->key->xkbInfo->desc;
  	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
  		XkbAction *act;
  		unsigned char mask;
-@@ -303,7 +300,7 @@ size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
-
+@@ -315,7 +312,7 @@ size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+ 
  	count = 0;
-
+ 
 -	master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
 +	master = vncKeyboardDev->master;
  	xkb = master->key->xkbInfo->desc;
  	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
  		XkbAction *act;
-@@ -359,7 +356,7 @@ KeyCode vncPressLevelThree(void)
+@@ -371,7 +368,7 @@ KeyCode vncPressLevelThree(void)
  			return 0;
  	}
-
+ 
 -	xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 +	xkb = vncKeyboardDev->master->key->xkbInfo->desc;
-
+ 
  	act = XkbKeyActionPtr(xkb, keycode, state);
  	if (act == NULL)
-@@ -390,7 +387,7 @@ size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
-
+@@ -402,7 +399,7 @@ size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+ 
  	count = 0;
-
+ 
 -	master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
 +	master = vncKeyboardDev->master;
  	xkb = master->key->xkbInfo->desc;
  	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
  		XkbAction *act;
-@@ -433,7 +430,7 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
- 	if (new_state != NULL)
+@@ -447,7 +444,7 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
  		*new_state = state;
-
+ 
+ 	fallback = 0;
 -	xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 +	xkb = vncKeyboardDev->master->key->xkbInfo->desc;
  	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
  		unsigned int state_out;
  		KeySym dummy;
-@@ -511,7 +508,7 @@ int vncIsAffectedByNumLock(KeyCode keycode)
+@@ -551,7 +548,7 @@ int vncIsAffectedByNumLock(KeyCode keycode)
  	if (numlock_keycode == 0)
  		return 0;
-
+ 
 -	xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 +	xkb = vncKeyboardDev->master->key->xkbInfo->desc;
-
+ 
  	act = XkbKeyActionPtr(xkb, numlock_keycode, state);
  	if (act == NULL)
-@@ -545,7 +542,7 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+@@ -585,7 +582,7 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
  	KeySym *syms;
  	KeySym upper, lower;
-
+ 
 -	master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
 +	master = vncKeyboardDev->master;
  	xkb = master->key->xkbInfo->desc;
diff --git a/SOURCES/tigervnc-manpages.patch b/SOURCES/tigervnc-manpages.patch
deleted file mode 100644
index 8e4b9c9..0000000
--- a/SOURCES/tigervnc-manpages.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-diff --git a/unix/vncserver b/unix/vncserver
-index 9e7a6ac..139f960 100755
---- a/unix/vncserver
-+++ b/unix/vncserver
-@@ -684,6 +684,7 @@ sub Usage
- 	"                 [-geometry <width>x<height>]\n".
- 	"                 [-pixelformat rgbNNN|bgrNNN]\n".
- 	"                 [-fp <font-path>]\n".
-+	"                 [-cc <visual>]\n".
- 	"                 [-fg]\n".
- 	"                 [-autokill]\n".
- 	"                 [-noxstartup]\n".
-diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
-index f076565..05669a4 100644
---- a/vncviewer/vncviewer.cxx
-+++ b/vncviewer/vncviewer.cxx
-@@ -352,6 +352,11 @@ static void usage(const char *programName)
-           "       %s [parameters] -listen [port] [parameters]\n"
-           "       %s [parameters] [.tigervnc file]\n",
-           programName, programName, programName);
-+  fprintf(stderr,"\n"
-+	  "Options:\n\n"
-+	  "  -display Xdisplay - Specifies the X display for the viewer window\n"
-+	  "  -geometry geometry - Standard X position and sizing specification.\n");
-+
-   fprintf(stderr,"\n"
-           "Parameters can be turned on with -<param> or off with -<param>=0\n"
-           "Parameters which take a value can be specified as "
diff --git a/SOURCES/tigervnc-passwd-crash-with-malloc-checks.patch b/SOURCES/tigervnc-passwd-crash-with-malloc-checks.patch
index cf9abae..7377822 100644
--- a/SOURCES/tigervnc-passwd-crash-with-malloc-checks.patch
+++ b/SOURCES/tigervnc-passwd-crash-with-malloc-checks.patch
@@ -1,13 +1,41 @@
+diff --git a/common/rfb/Password.cxx b/common/rfb/Password.cxx
+index e4a508c..f555c57 100644
+--- a/common/rfb/Password.cxx
++++ b/common/rfb/Password.cxx
+@@ -55,7 +55,7 @@ PlainPasswd::~PlainPasswd() {
+ 
+ void PlainPasswd::replaceBuf(char* b) {
+   if (buf)
+-    memset(buf, 0, strlen(buf));
++    memset(buf, 0, length ? length : strlen(buf));
+   CharArray::replaceBuf(b);
+ }
+ 
 diff --git a/common/rfb/util.h b/common/rfb/util.h
-index b678b89..9e59bd3 100644
+index 3100f90..764692a 100644
 --- a/common/rfb/util.h
 +++ b/common/rfb/util.h
-@@ -50,7 +50,7 @@ namespace rfb {
+@@ -51,16 +51,21 @@ namespace rfb {
      CharArray() : buf(0) {}
      CharArray(char* str) : buf(str) {} // note: assumes ownership
-     CharArray(int len) {
--      buf = new char[len];
-+      buf = new char[len]();
+     CharArray(size_t len) {
++      length = len;
+       buf = new char[len]();
      }
      ~CharArray() {
-       delete [] buf;
+-      delete [] buf;
++      if (buf) {
++        delete [] buf;
++        buf = nullptr;
++      }
+     }
+     void format(const char *fmt, ...) __printf_attr(2, 3);
+     // Get the buffer pointer & clear it (i.e. caller takes ownership)
+     char* takeBuf() {char* tmp = buf; buf = 0; return tmp;}
+-    void replaceBuf(char* b) {delete [] buf; buf = b;}
++    void replaceBuf(char* b) {if (buf) delete [] buf; buf = b;}
+     char* buf;
++    size_t length = 0;
+   private:
+     CharArray(const CharArray&);
+     CharArray& operator=(const CharArray&);
diff --git a/SOURCES/tigervnc-provide-correct-dimensions-for-xshm-setup.patch b/SOURCES/tigervnc-provide-correct-dimensions-for-xshm-setup.patch
new file mode 100644
index 0000000..cefc769
--- /dev/null
+++ b/SOURCES/tigervnc-provide-correct-dimensions-for-xshm-setup.patch
@@ -0,0 +1,57 @@
+From 0f1ded057dbf875e69a0d72418d95610db8fa6a3 Mon Sep 17 00:00:00 2001
+From: Pierre Ossman <ossman@cendio.se>
+Date: Mon, 30 Dec 2019 10:50:52 +0100
+Subject: [PATCH] Provide correct dimensions for XShm setup
+
+Since 53f913a we initialize the underlying PixelBuffer with 0x0
+dimensions, which means we need to keep more explicit track of what
+we are trying to allocate in the setup methods.
+---
+ vncviewer/PlatformPixelBuffer.cxx | 6 +++---
+ vncviewer/PlatformPixelBuffer.h   | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
+index 61f7b743b..59e51d596 100644
+--- a/vncviewer/PlatformPixelBuffer.cxx
++++ b/vncviewer/PlatformPixelBuffer.cxx
+@@ -43,7 +43,7 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) :
+ #endif
+ {
+ #if !defined(WIN32) && !defined(__APPLE__)
+-  if (!setupShm()) {
++  if (!setupShm(width, height)) {
+     xim = XCreateImage(fl_display, CopyFromParent, 32,
+                        ZPixmap, 0, 0, width, height, 32, 0);
+     if (!xim)
+@@ -136,7 +136,7 @@ static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error)
+   return 0;
+ }
+ 
+-bool PlatformPixelBuffer::setupShm()
++bool PlatformPixelBuffer::setupShm(int width, int height)
+ {
+   int major, minor;
+   Bool pixmaps;
+@@ -153,7 +153,7 @@ bool PlatformPixelBuffer::setupShm()
+   shminfo = new XShmSegmentInfo;
+ 
+   xim = XShmCreateImage(fl_display, CopyFromParent, 32,
+-                        ZPixmap, 0, shminfo, width(), height());
++                        ZPixmap, 0, shminfo, width, height);
+   if (!xim)
+     goto free_shminfo;
+ 
+diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h
+index f9038cd9c..ec439f64f 100644
+--- a/vncviewer/PlatformPixelBuffer.h
++++ b/vncviewer/PlatformPixelBuffer.h
+@@ -53,7 +53,7 @@ class PlatformPixelBuffer: public rfb::FullFramePixelBuffer, public Surface {
+ 
+ #if !defined(WIN32) && !defined(__APPLE__)
+ protected:
+-  bool setupShm();
++  bool setupShm(int width, int height);
+ 
+ protected:
+   XShmSegmentInfo *shminfo;
diff --git a/SOURCES/tigervnc-shebang.patch b/SOURCES/tigervnc-shebang.patch
deleted file mode 100644
index f76af87..0000000
--- a/SOURCES/tigervnc-shebang.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff -up tigervnc-1.3.0/unix/vncserver.shebang tigervnc-1.3.0/unix/vncserver
---- tigervnc-1.3.0/unix/vncserver.shebang	2013-07-24 12:22:34.962158378 +0100
-+++ tigervnc-1.3.0/unix/vncserver	2013-07-24 12:22:41.593188190 +0100
-@@ -1,4 +1,4 @@
--#!/usr/bin/env perl
-+#!/usr/bin/perl
- #
- #  Copyright (C) 2009-2010 D. R. Commander.  All Rights Reserved.
- #  Copyright (C) 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
diff --git a/SOURCES/tigervnc-systemd-support.patch b/SOURCES/tigervnc-systemd-support.patch
new file mode 100644
index 0000000..03a3d28
--- /dev/null
+++ b/SOURCES/tigervnc-systemd-support.patch
@@ -0,0 +1,2163 @@
+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..97fa075
+--- /dev/null
++++ b/unix/vncserver/selinux/vncsession.fc
+@@ -0,0 +1,23 @@
++#
++#  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.
++#
++
++/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..43242e6
+--- /dev/null
++++ b/unix/vncserver/selinux/vncsession.te
+@@ -0,0 +1,57 @@
++#
++#  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);
++
++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;
++
++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)
++
++# To create the log file in the user home directory
++allow vnc_session_t file_type:dir search_dir_perms;
++userdom_user_home_dir_filetrans_user_home_content(vnc_session_t, dir, ".vnc");
++userdom_manage_user_home_content_dirs(vnc_session_t);
++userdom_manage_user_home_content_files(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
+ 
diff --git a/SOURCES/tigervnc-vncserver-do-not-return-returncode-indicating-error.patch b/SOURCES/tigervnc-vncserver-do-not-return-returncode-indicating-error.patch
deleted file mode 100644
index 1361d8b..0000000
--- a/SOURCES/tigervnc-vncserver-do-not-return-returncode-indicating-error.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/unix/vncserver b/unix/vncserver
-index bb4f2feb..68be032d 100755
---- a/unix/vncserver
-+++ b/unix/vncserver
-@@ -709,7 +709,7 @@ sub List
- 	    }
- 	}
-     }
--    exit 1;
-+    exit;
- }
- 
- 
diff --git a/SOURCES/tigervnc-xstartup.patch b/SOURCES/tigervnc-xstartup.patch
deleted file mode 100644
index 7098941..0000000
--- a/SOURCES/tigervnc-xstartup.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-diff --git a/unix/vncserver b/unix/vncserver
-index bb4f2feb..b038dd3b 100755
---- a/unix/vncserver
-+++ b/unix/vncserver
-@@ -58,27 +58,14 @@ $defaultXStartup
-     = ("#!/bin/sh\n\n".
-        "unset SESSION_MANAGER\n".
-        "unset DBUS_SESSION_BUS_ADDRESS\n".
--       "OS=`uname -s`\n".
--       "if [ \$OS = 'Linux' ]; then\n".
--       "  case \"\$WINDOWMANAGER\" in\n".
--       "    \*gnome\*)\n".
--       "      if [ -e /etc/SuSE-release ]; then\n".
--       "        PATH=\$PATH:/opt/gnome/bin\n".
--       "        export PATH\n".
--       "      fi\n".
--       "      ;;\n".
--       "  esac\n".
--       "fi\n".
--       "if [ -x /etc/X11/xinit/xinitrc ]; then\n".
--       "  exec /etc/X11/xinit/xinitrc\n".
--       "fi\n".
--       "if [ -f /etc/X11/xinit/xinitrc ]; then\n".
--       "  exec sh /etc/X11/xinit/xinitrc\n".
--       "fi\n".
--       "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n".
--       "xsetroot -solid grey\n".
--       "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n".
--       "twm &\n");
-+       "/etc/X11/xinit/xinitrc\n".
-+       "# Assume either Gnome will be started by default when installed\n".
-+       "# We want to kill the session automatically in this case when user logs out. In case you modify\n".
-+       "# /etc/X11/xinit/Xclients or ~/.Xclients yourself to achieve a different result, then you should\n".
-+       "# be responsible to modify below code to avoid that your session will be automatically killed\n".
-+       "if [ -e /usr/bin/gnome-session ]; then\n".
-+       "    vncserver -kill \$DISPLAY\n".
-+       "fi\n");
- 
- $defaultConfig
-     = ("## Supported server options to pass to vncserver upon invocation can be listed\n".
diff --git a/SOURCES/vncserver-system.service b/SOURCES/vncserver-system.service
deleted file mode 100644
index 7b9cb2f..0000000
--- a/SOURCES/vncserver-system.service
+++ /dev/null
@@ -1,45 +0,0 @@
-# The vncserver service unit file
-#
-# Quick HowTo:
-# 1. Copy this file to /etc/systemd/system/vncserver@.service
-# 2. Replace <USER> with the actual user name and edit vncserver
-#    parameters in the wrapper script located in /usr/bin/vncserver_wrapper
-# 3. Run `systemctl daemon-reload`
-# 4. Run `systemctl enable 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=simple
-
-# Clean any existing files in /tmp/.X11-unix environment
-ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
-ExecStart=/usr/bin/vncserver_wrapper <USER> %i
-ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
-
-[Install]
-WantedBy=multi-user.target
diff --git a/SOURCES/vncserver-user.service b/SOURCES/vncserver-user.service
deleted file mode 100644
index aed01e0..0000000
--- a/SOURCES/vncserver-user.service
+++ /dev/null
@@ -1,59 +0,0 @@
-# The vncserver service unit file
-#
-# Quick HowTo: As the User wanting to have this functionality
-#
-# 1. Copy this file to ~/.config/systemd/user/ (Optional, in case default settings are not suitable)
-#
-#   $ mkdir -p ~/.config/systemd/user
-#   $ cp /usr/lib/systemd/user/vncserver@.service ~/.config/systemd/user/
-#
-# 2. Reload user's systemd
-#
-#    $ systemctl --user daemon-reload
-#
-# 3. Start the service immediately and enable it at boot
-#
-#    $ systemctl --user enable vncserver@:<display>.service --now
-#
-# 4. Enable lingering
-#
-#    $ loginctl enable-linger
-#
-# 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
-
-ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
-ExecStart=/usr/bin/vncserver %i
-ExecStop=/usr/bin/vncserver -kill %i
-
-Restart=on-success
-RestartSec=15
-
-[Install]
-WantedBy=default.target
diff --git a/SOURCES/vncserver.sysconfig b/SOURCES/vncserver.sysconfig
deleted file mode 100644
index 4d0489b..0000000
--- a/SOURCES/vncserver.sysconfig
+++ /dev/null
@@ -1 +0,0 @@
-# THIS FILE HAS BEEN REPLACED BY /lib/systemd/system/vncserver@.service
diff --git a/SOURCES/vncserver_wrapper b/SOURCES/vncserver_wrapper
deleted file mode 100755
index 0c8f994..0000000
--- a/SOURCES/vncserver_wrapper
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-
-USER="$1"
-INSTANCE="$2"
-
-die() {
-	echo "FATAL: ${@:-}" >&2
-	exit 2
-}
-
-cleanup() {
-	[ -n "$VNCPID" ] || return
-	if kill -0 $VNCPID 2>/dev/null; then
-		kill $VNCPID
-	fi
-}
-
-trap cleanup TERM INT HUP
-
-[ -n "$USER" -a -n "$INSTANCE" ] || die "Invalid usage!"
-
-/usr/sbin/runuser -l "$USER" -c "/usr/bin/vncserver ${INSTANCE}"
-[ $? -eq 0 ] || die "'runuser -l $USER' failed!"
-
-# Wait up to 5 seconds for vncserver to be up
-for tries in $(seq 1 50); do
-	[ -e "~$USER/.vnc/$(hostname)${INSTANCE}.pid" ] && break
-	sleep 0.1
-done
-
-eval HOME=~$USER
-
-VNCPID=$(cat "$HOME/.vnc/$(hostname)${INSTANCE}.pid" 2>/dev/null || true)
-[ -n "$VNCPID" ] || die "'vncserver ${INSTANCE}' failed to start after 5 seconds!"
-
-echo "'vncserver ${INSTANCE}' has PID $VNCPID, waiting until it exits ..."
-
-while kill -0 $VNCPID 2>/dev/null; do
-	sleep 5
-done
-
-echo "PID $VNCPID exited, exiting ..."
diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec
index 9d3470b..b4a3f67 100644
--- a/SPECS/tigervnc.spec
+++ b/SPECS/tigervnc.spec
@@ -1,6 +1,6 @@
 Name:           tigervnc
-Version:        1.9.0
-Release:        13%{?dist}
+Version:        1.10.1
+Release:        1%{?dist}
 Summary:        A TigerVNC remote display system
 
 %global _hardened_build 1
@@ -9,28 +9,22 @@ License:        GPLv2+
 URL:            http://www.tigervnc.com
 
 Source0:        %{name}-%{version}.tar.gz
-Source1:        vncserver-system.service
-Source2:        vncserver-user.service
-Source3:        vncserver.sysconfig
-Source4:        10-libvnc.conf
-Source5:        xvnc.service
-Source6:        xvnc.socket
-Source7:        vncserver_wrapper
-
-Patch1:         tigervnc-manpages.patch
+Source1:        xvnc.service
+Source2:        xvnc.socket
+Source3:        10-libvnc.conf
+
 Patch2:         tigervnc-getmaster.patch
-Patch3:         tigervnc-shebang.patch
-Patch4:         tigervnc-xstartup.patch
 Patch5:         tigervnc-cursor.patch
 Patch6:         tigervnc-1.3.1-CVE-2014-8240.patch
-Patch7:         tigervnc-1.3.1-do-not-die-when-port-is-already-taken.patch
 Patch8:         tigervnc-let-user-know-about-not-using-view-only-password.patch
 Patch9:         tigervnc-working-tls-on-fips-systems.patch
 Patch11:        tigervnc-utilize-system-crypto-policies.patch
 Patch12:        tigervnc-passwd-crash-with-malloc-checks.patch
-Patch13:        tigervnc-vncserver-do-not-return-returncode-indicating-error.patch
+Patch13:        0001-xserver-add-no-op-input-thread-init-function.patch
+Patch14:        tigervnc-provide-correct-dimensions-for-xshm-setup.patch
 
-Patch50:        tigervnc-covscan.patch
+# Upstream patches
+Patch50:        tigervnc-systemd-support.patch
 
 # This is tigervnc-%%{version}/unix/xserver116.patch rebased on the latest xorg
 Patch100:       tigervnc-xserver120.patch
@@ -42,12 +36,11 @@ BuildRequires:  libX11-devel, automake, autoconf, libtool, gettext, gettext-auto
 BuildRequires:  libXext-devel, xorg-x11-server-source, libXi-devel
 BuildRequires:  xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel
 BuildRequires:  libxkbfile-devel, openssl-devel, libpciaccess-devel
-BuildRequires:  mesa-libGL-devel, libXinerama-devel
+BuildRequires:  mesa-libGL-devel, libXinerama-devel, xorg-x11-font-utils
 BuildRequires:  freetype-devel, libXdmcp-devel, libxshmfence-devel
-BuildRequires:  desktop-file-utils, java-devel, jpackage-utils
 BuildRequires:  libjpeg-turbo-devel, gnutls-devel, pam-devel
 BuildRequires:  libdrm-devel, libXt-devel, pixman-devel
-BuildRequires:  systemd, cmake
+BuildRequires:  systemd, cmake, desktop-file-utils, selinux-policy-devel
 %if 0%{?fedora} > 24 || 0%{?rhel} >= 7
 BuildRequires:  libXfont2-devel
 %else
@@ -79,7 +72,8 @@ server.
 %package server
 Summary:        A TigerVNC server
 Requires:       perl-interpreter
-Requires:       tigervnc-server-minimal
+Requires:       tigervnc-server-minimal = %{version}-%{release}
+Requires:       tigervnc-selinux = %{version}-%{release}
 Requires:       xorg-x11-xauth
 Requires:       xorg-x11-xinit
 Requires(post): systemd
@@ -100,7 +94,7 @@ Requires(post): chkconfig
 Requires(preun):chkconfig
 
 Requires:       mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils
-Requires:       tigervnc-license
+Requires:       tigervnc-license, dbus-x11
 
 %description server-minimal
 The VNC system allows you to access the same desktop from a wide
@@ -119,15 +113,6 @@ This package contains libvnc.so module to X server, allowing others
 to access the desktop on your machine.
 %endif
 
-%package server-applet
-Summary:        Java TigerVNC viewer applet for TigerVNC server
-Requires:       tigervnc-server, java, jpackage-utils
-BuildArch:      noarch
-
-%description server-applet
-The Java TigerVNC viewer applet for web browsers. Install this package to allow
-clients to use web browser when connect to the TigerVNC server.
-
 %package license
 Summary:        License of TigerVNC suite
 BuildArch:      noarch
@@ -142,6 +127,18 @@ BuildArch:      noarch
 %description icons
 This package contains icons for TigerVNC viewer
 
+%package selinux
+Summary:        SELinux module for TigerVNC
+BuildArch:      noarch
+Requires(pre):  libselinux-utils
+Requires(post): selinux-policy >= %{_selinux_policy_version}
+Requires(post): policycoreutils
+Requires(post): libselinux-utils
+
+%description selinux
+This package provides the SELinux policy module to ensure TigerVNC
+runs properly under an environment with SELinux enabled.
+
 %prep
 %setup -q
 
@@ -154,19 +151,9 @@ done
 %patch101 -p1 -b .rpath
 popd
 
-# Synchronise manpages and --help output (bug #980870).
-%patch1 -p1 -b .manpages
-
 # libvnc.so: don't use unexported GetMaster function (bug #744881 again).
 %patch2 -p1 -b .getmaster
 
-# Don't use shebang in vncserver script.
-%patch3 -p1 -b .shebang
-
-# Clearer xstartup file (bug #923655).
-# Bug 1665876 - Tigervnc not starting on RHEL 7.6 server without -noxstartup option
-%patch4  -p1 -b .xstartup
-
 # Fixed viewer crash when cursor has not been set (bug #1051333).
 %patch5 -p1 -b .cursor
 
@@ -174,9 +161,6 @@ popd
 # buffer overflow in screen size handling
 %patch6 -p1 -b .tigervnc-1.3.1-CVE-2014-8240
 
-# Bug 1322155 - Xorg socket conflict for VNC port 5901
-%patch7 -p1 -b .do-not-die-when-port-is-already-taken
-
 # Bug 1447555 - view-only accepts enter, unclear whether default password is generated or not
 %patch8 -p1 -b .let-user-know-about-not-using-view-only-password
 
@@ -188,9 +172,19 @@ popd
 
 %patch12 -p1 -b .passwd-crash-with-malloc-checks
 
-%patch13 -p1 -b .vncserver-do-not-return-returncode-indicating-error
+%patch13 -p1 -b .xserver-add-no-op-input-thread-init-function.
+
+%patch14 -p1 -b .provide-correct-dimensions-for-xshm-setup
 
-%patch50 -p1 -b .tigervnc-covscan
+# HACK make sure we are able to successfuly apply a patch. This is because we will
+# be creating a directory under name which already exists as a file and it also seems
+# to be not possible to create a directory with a patch
+pushd unix
+rm vncserver
+mkdir vncserver
+popd
+
+%patch50 -p1 -b .tigervnc-systemd-support
 
 %build
 %ifarch sparcv9 sparc64 s390 s390x
@@ -230,12 +224,12 @@ pushd media
 make
 popd
 
-# Build Java applet
-pushd java
-%{cmake} .
-JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8" make
+# SELinux
+pushd unix/vncserver/selinux
+make
 popd
 
+
 %install
 %make_install
 rm -f %{buildroot}%{_docdir}/%{name}-%{version}/{README.rst,LICENCE.TXT}
@@ -244,20 +238,14 @@ pushd unix/xserver/hw/vnc
 make install DESTDIR=%{buildroot}
 popd
 
-# Install systemd unit file
-mkdir -p %{buildroot}%{_unitdir}
-mkdir -p %{buildroot}%{_userunitdir}
-install -m644 %{SOURCE1} %{buildroot}%{_unitdir}/vncserver@.service
-install -m644 %{SOURCE2} %{buildroot}%{_userunitdir}/vncserver@.service
-install -m644 %{SOURCE5} %{buildroot}%{_unitdir}/xvnc@.service
-install -m644 %{SOURCE6} %{buildroot}%{_unitdir}/xvnc.socket
-rm -rf %{buildroot}%{_initrddir}
+pushd unix/vncserver/selinux
+make install DESTDIR=%{buildroot}
+popd
 
-# Install vncserver wrapper script
-install -m744 %{SOURCE7} %{buildroot}%{_bindir}/vncserver_wrapper
 
-mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
-install -m644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/vncservers
+# Install systemd unit file
+install -m644 %{SOURCE1} %{buildroot}%{_unitdir}/xvnc@.service
+install -m644 %{SOURCE2} %{buildroot}%{_unitdir}/xvnc.socket
 
 # Install desktop stuff
 mkdir -p %{buildroot}%{_datadir}/icons/hicolor/{16x16,24x24,48x48}/apps
@@ -269,13 +257,6 @@ done
 popd
 
 
-# Install Java applet
-pushd java
-mkdir -p %{buildroot}%{_datadir}/vnc/classes
-install -m755 VncViewer.jar %{buildroot}%{_datadir}/vnc/classes
-install -m644 com/tigervnc/vncviewer/index.vnc %{buildroot}%{_datadir}/vnc/classes
-popd
-
 %find_lang %{name} %{name}.lang
 
 # remove unwanted files
@@ -285,24 +266,38 @@ rm -f  %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la
 rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.so
 %else
 mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/
-install -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
+install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
 %endif
 
 %post server
-%systemd_post vncserver.service
 %systemd_post xvnc.service
 %systemd_post xvnc.socket
 
 %preun server
-%systemd_preun vncserver.service
 %systemd_preun xvnc.service
 %systemd_preun xvnc.socket
 
 %postun server
-%systemd_postun vncserver.service
 %systemd_postun xvnc.service
 %systemd_postun xvnc.socket
 
+%pre selinux
+%selinux_relabel_pre
+
+%post selinux
+%selinux_modules_install %{_datadir}/selinux/packages/vncsession.pp
+%selinux_relabel_post
+
+%posttrans selinux
+%selinux_relabel_post
+
+%postun selinux
+%selinux_modules_uninstall vncsession
+if [ $1 -eq 0 ]; then
+    %selinux_relabel_post
+fi
+
+
 %files -f %{name}.lang
 %doc README.rst
 %{_bindir}/vncviewer
@@ -310,16 +305,20 @@ install -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.c
 %{_mandir}/man1/vncviewer.1*
 
 %files server
-%config(noreplace) %{_sysconfdir}/sysconfig/vncservers
-%{_userunitdir}/vncserver@.service
+%config(noreplace) %{_sysconfdir}/pam.d/tigervnc
+%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults
+%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory
+%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users
 %{_unitdir}/vncserver@.service
 %{_unitdir}/xvnc@.service
 %{_unitdir}/xvnc.socket
 %{_bindir}/x0vncserver
-%{_bindir}/vncserver
-%{_bindir}/vncserver_wrapper
-%{_mandir}/man1/vncserver.1*
+%{_sbindir}/vncsession
+%{_libexecdir}/vncserver
+%{_libexecdir}/vncsession-start
 %{_mandir}/man1/x0vncserver.1*
+%{_mandir}/man8/vncserver.8*
+%{_mandir}/man8/vncsession.8*
 
 %files server-minimal
 %{_bindir}/vncconfig
@@ -335,17 +334,24 @@ install -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.c
 %config %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
 %endif
 
-%files server-applet
-%doc java/com/tigervnc/vncviewer/README
-%{_datadir}/vnc/classes/*
-
 %files license
-%license LICENCE.TXT
+%{_docdir}/tigervnc/LICENCE.TXT
 
 %files icons
 %{_datadir}/icons/hicolor/*/apps/*
 
+%files selinux
+%{_datadir}/selinux/packages/vncsession.pp
+
+
 %changelog
+* Mon Apr 27 2020 Jan Grulich <jgrulich@redhat.com> - 1.10.1-1
+- Update to 1.10.1
+  Resolves: bz#1806992
+
+- Add proper systemd support
+  Resolves: bz#1790443
+
 * Tue Jan 28 2020 Jan Grulich <jgrulich@redhat.com> - 1.9.0-13
 - Bump build because of z-stream
   Resolves: bz#1671714