import tigervnc-1.12.0-12.el9

c9-beta imports/c9-beta/tigervnc-1.12.0-12.el9
CentOS Sources 2 years ago committed by MSVSphere Packaging Team
commit 698c03e746

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/tigervnc-1.12.0.tar.gz

@ -0,0 +1 @@
44db63993d8ad04f730b0b48e8aca32933bff15a SOURCES/tigervnc-1.12.0.tar.gz

@ -0,0 +1,24 @@
From 2489f2f38eb32d9dd03718a36cbdbdf13d2f8b9b Mon Sep 17 00:00:00 2001
From: Adam Jackson <ajax@redhat.com>
Date: Thu, 12 Nov 2015 11:10:11 -0500
Subject: [PATCH] rpath hack
Normally, rpath is undesirable. But for the X server we _know_ we need
Mesa's libGL, which will always be in %{_libdir}, and not any third-party
libGL that may be configured using ld.so.conf.
---
configure.ac | 1 +
1 files changed, 1 insertions(+), 0 deletion(-)
diff --git a/configure.ac b/configure.ac
index fa15a2d..a5af1e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1261,6 +1261,7 @@ AM_CONDITIONAL(GLX, test "x$GLX" = xyes)
AM_CONDITIONAL(HASHTABLE, test "x$HASHTABLE" = xyes)
+GLX_SYS_LIBS="$GLX_SYS_LIBS -Wl,-rpath=\$(libdir)"
AC_SUBST([GLX_DEFINES])
AC_SUBST([GLX_SYS_LIBS])

@ -0,0 +1,19 @@
# This file contains configuration of libvnc.so module
#
# To get libvnc.so module working, do this:
# 1. run "vncpasswd" from tigervnc-server package as root user
# 2. uncomment configuration lines below
#
# Please note you can specify any option which Xvnc accepts.
# Refer to `Xvnc -help` output for detailed list of options.
#Section "Module"
# Load "vnc"
#EndSection
#Section "Screen"
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
# Option "PasswordFile" "/root/.vnc/passwd"
#EndSection

@ -0,0 +1,199 @@
From ccbd491fa48f1c43daeb1a6c5ee91a1a8fa3db88 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 9 Aug 2022 14:31:07 +0200
Subject: [PATCH] x0vncserver: add new keysym in case we don't find a matching
keycode
We might often fail to find a matching X11 keycode when the client has
a different keyboard layout and end up with no key event. To avoid a
failure we add it as a new keysym/keycode pair so the next time a keysym
from the client that is unknown to the server is send, we will find a
match and proceed with key event. This is same behavior used in Xvnc or
x11vnc, although Xvnc has more advanced mapping from keysym to keycode.
---
unix/x0vncserver/XDesktop.cxx | 121 +++++++++++++++++++++++++++++++++-
unix/x0vncserver/XDesktop.h | 4 ++
2 files changed, 122 insertions(+), 3 deletions(-)
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index f2046e43e..933998f05 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -31,6 +31,7 @@
#include <x0vncserver/XDesktop.h>
#include <X11/XKBlib.h>
+#include <X11/Xutil.h>
#ifdef HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
@@ -50,6 +51,7 @@ void vncSetGlueContext(Display *dpy, void *res);
#include <x0vncserver/Geometry.h>
#include <x0vncserver/XPixelBuffer.h>
+using namespace std;
using namespace rfb;
extern const unsigned short code_map_qnum_to_xorgevdev[];
@@ -264,6 +266,9 @@ void XDesktop::start(VNCServer* vs) {
void XDesktop::stop() {
running = false;
+ // Delete added keycodes
+ deleteAddedKeysyms(dpy);
+
#ifdef HAVE_XDAMAGE
if (haveDamage)
XDamageDestroy(dpy, damage);
@@ -383,6 +388,118 @@ KeyCode XDesktop::XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
}
#endif
+KeyCode XDesktop::addKeysym(Display* dpy, KeySym keysym)
+{
+ int types[1];
+ unsigned int key;
+ XkbDescPtr xkb;
+ XkbMapChangesRec changes;
+ KeySym *syms;
+ KeySym upper, lower;
+
+ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+
+ if (!xkb)
+ return 0;
+
+ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
+ if (XkbKeyNumGroups(xkb, key) == 0)
+ break;
+ }
+
+ if (key < xkb->min_key_code)
+ return 0;
+
+ memset(&changes, 0, sizeof(changes));
+
+ XConvertCase(keysym, &lower, &upper);
+
+ if (upper == lower)
+ types[XkbGroup1Index] = XkbOneLevelIndex;
+ else
+ types[XkbGroup1Index] = XkbAlphabeticIndex;
+
+ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes);
+
+ syms = XkbKeySymsPtr(xkb,key);
+ if (upper == lower)
+ syms[0] = keysym;
+ else {
+ syms[0] = lower;
+ syms[1] = upper;
+ }
+
+ changes.changed |= XkbKeySymsMask;
+ changes.first_key_sym = key;
+ changes.num_key_syms = 1;
+
+ if (XkbChangeMap(dpy, xkb, &changes)) {
+ vlog.info("Added unknown keysym %s to keycode %d", XKeysymToString(keysym), key);
+ addedKeysyms[keysym] = key;
+ return key;
+ }
+
+ return 0;
+}
+
+void XDesktop::deleteAddedKeysyms(Display* dpy) {
+ XkbDescPtr xkb;
+ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+
+ if (!xkb)
+ return;
+
+ XkbMapChangesRec changes;
+ memset(&changes, 0, sizeof(changes));
+
+ KeyCode lowestKeyCode = xkb->max_key_code;
+ KeyCode highestKeyCode = xkb->min_key_code;
+ std::map<KeySym, KeyCode>::iterator it;
+ for (it = addedKeysyms.begin(); it != addedKeysyms.end(); it++) {
+ if (XkbKeyNumGroups(xkb, it->second) != 0) {
+ // Check if we are removing keysym we added ourself
+ if (XkbKeysymToKeycode(dpy, it->first) != it->second)
+ continue;
+
+ XkbChangeTypesOfKey(xkb, it->second, 0, XkbGroup1Mask, NULL, &changes);
+
+ if (it->second < lowestKeyCode)
+ lowestKeyCode = it->second;
+
+ if (it->second > highestKeyCode)
+ highestKeyCode = it->second;
+ }
+ }
+
+ changes.changed |= XkbKeySymsMask;
+ changes.first_key_sym = lowestKeyCode;
+ changes.num_key_syms = highestKeyCode - lowestKeyCode + 1;
+ XkbChangeMap(dpy, xkb, &changes);
+
+ addedKeysyms.clear();
+}
+
+KeyCode XDesktop::keysymToKeycode(Display* dpy, KeySym keysym) {
+ int keycode = 0;
+
+ // XKeysymToKeycode() doesn't respect state, so we have to use
+ // something slightly more complex
+ keycode = XkbKeysymToKeycode(dpy, keysym);
+
+ if (keycode != 0)
+ return keycode;
+
+ // TODO: try to further guess keycode with all possible mods as Xvnc does
+
+ keycode = addKeysym(dpy, keysym);
+
+ if (keycode == 0)
+ vlog.error("Failure adding new keysym 0x%lx", keysym);
+
+ return keycode;
+}
+
+
void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
#ifdef HAVE_XTEST
int keycode = 0;
@@ -398,9 +515,7 @@ void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
if (pressedKeys.find(keysym) != pressedKeys.end())
keycode = pressedKeys[keysym];
else {
- // XKeysymToKeycode() doesn't respect state, so we have to use
- // something slightly more complex
- keycode = XkbKeysymToKeycode(dpy, keysym);
+ keycode = keysymToKeycode(dpy, keysym);
}
}
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index 840d43316..6ebcd9f8a 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -55,6 +55,9 @@ class XDesktop : public rfb::SDesktop,
const char* userName);
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
+ KeyCode addKeysym(Display* dpy, KeySym keysym);
+ void deleteAddedKeysyms(Display* dpy);
+ KeyCode keysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
virtual void clientCutText(const char* str);
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
@@ -78,6 +81,7 @@ class XDesktop : public rfb::SDesktop,
bool haveXtest;
bool haveDamage;
int maxButtons;
+ std::map<KeySym, KeyCode> addedKeysyms;
std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE

@ -0,0 +1,117 @@
From f783d5c8b567199178b6690f347e060a69d2aa36 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Thu, 11 Aug 2022 13:15:29 +0200
Subject: [PATCH] x0vncserver: update/display cursor only on correct screen in
zaphod mode
We have to check whether we update cursor position/shape only in case
the cursor is on our display, otherwise in zaphod mode, ie. when having
two instances of x0vncserver on screens :0.0 and :0.1 we would be having
the cursor duplicated and actually not funcional (aka ghost cursor) as
it would be actually not present. We also additionally watch EnterNotify
and LeaveNotify events in order to show/hide cursor accordingly.
Change made with help from Olivier Fourdan <ofourdan@redhat.com>
---
unix/x0vncserver/XDesktop.cxx | 60 +++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 7 deletions(-)
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index f2046e43e..f07fd78bf 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -192,7 +192,8 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask);
/* Override TXWindow::init input mask */
XSelectInput(dpy, DefaultRootWindow(dpy),
- PropertyChangeMask | StructureNotifyMask | ExposureMask);
+ PropertyChangeMask | StructureNotifyMask |
+ ExposureMask | EnterWindowMask | LeaveWindowMask);
} else {
#endif
vlog.info("RANDR extension not present");
@@ -217,11 +218,13 @@ void XDesktop::poll() {
Window root, child;
int x, y, wx, wy;
unsigned int mask;
- XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
- &x, &y, &wx, &wy, &mask);
- x -= geometry->offsetLeft();
- y -= geometry->offsetTop();
- server->setCursorPos(rfb::Point(x, y), false);
+
+ if (XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+ &x, &y, &wx, &wy, &mask)) {
+ x -= geometry->offsetLeft();
+ y -= geometry->offsetTop();
+ server->setCursorPos(rfb::Point(x, y), false);
+ }
}
}
@@ -253,7 +256,14 @@ void XDesktop::start(VNCServer* vs) {
#endif
#ifdef HAVE_XFIXES
- setCursor();
+ Window root, child;
+ int x, y, wx, wy;
+ unsigned int mask;
+ // Check whether the cursor is initially on our screen
+ if (XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+ &x, &y, &wx, &wy, &mask))
+ setCursor();
+
#endif
server->setLEDState(ledState);
@@ -701,6 +711,15 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
if (cev->subtype != XFixesDisplayCursorNotify)
return false;
+ Window root, child;
+ int x, y, wx, wy;
+ unsigned int mask;
+
+ // Check whether the cursor is initially on our screen
+ if (!XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+ &x, &y, &wx, &wy, &mask))
+ return false;
+
return setCursor();
#endif
#ifdef HAVE_XRANDR
@@ -753,6 +772,33 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
return true;
#endif
+#ifdef HAVE_XFIXES
+ } else if (ev->type == EnterNotify) {
+ XCrossingEvent* cev;
+
+ if (!running)
+ return true;
+
+ cev = (XCrossingEvent*)ev;
+
+ if (cev->window != cev->root)
+ return false;
+
+ return setCursor();
+ } else if (ev->type == LeaveNotify) {
+ XCrossingEvent* cev;
+
+ if (!running)
+ return true;
+
+ cev = (XCrossingEvent*)ev;
+
+ if (cev->window == cev->root)
+ return false;
+
+ server->setCursor(0, 0, Point(), NULL);
+ return true;
+#endif
}
return false;

@ -0,0 +1,34 @@
From 2daf4126882f82b6e392dfbae87205dbdc559c3d Mon Sep 17 00:00:00 2001
From: Pierre Ossman <ossman@cendio.se>
Date: Thu, 23 Dec 2021 15:58:00 +0100
Subject: [PATCH] Fix typo in mirror monitor detection
Bug introduced in fb561eb but still somehow passed manual testing.
Resulted in some stray reads off the end of the stack, which were
hopefully harmless.
---
vncviewer/MonitorIndicesParameter.cxx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/vncviewer/MonitorIndicesParameter.cxx b/vncviewer/MonitorIndicesParameter.cxx
index 5130831cb..4ac74dd1a 100644
--- a/vncviewer/MonitorIndicesParameter.cxx
+++ b/vncviewer/MonitorIndicesParameter.cxx
@@ -211,13 +211,13 @@ std::vector<MonitorIndicesParameter::Monitor> MonitorIndicesParameter::fetchMoni
// Only keep a single entry for mirrored screens
match = false;
for (int j = 0; j < ((int) monitors.size()); j++) {
- if (monitors[i].x != monitor.x)
+ if (monitors[j].x != monitor.x)
continue;
- if (monitors[i].y != monitor.y)
+ if (monitors[j].y != monitor.y)
continue;
- if (monitors[i].w != monitor.w)
+ if (monitors[j].w != monitor.w)
continue;
- if (monitors[i].h != monitor.h)
+ if (monitors[j].h != monitor.h)
continue;
match = true;

@ -0,0 +1,25 @@
From faf81b4b238e24fe29eb53f885a25367e212dd7b Mon Sep 17 00:00:00 2001
From: Zdenek Pytela <zpytela@redhat.com>
Date: Mon, 7 Feb 2022 10:45:41 +0100
Subject: [PATCH] SELinux: use /root/.vnc in file context specification
Instead of HOME_ROOT/.vnc, /root/.vnc should be used
for user root's home to specify default file context
as HOME_ROOT actually means base for home dirs (usually /home).
---
unix/vncserver/selinux/vncsession.fc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/unix/vncserver/selinux/vncsession.fc b/unix/vncserver/selinux/vncsession.fc
index 6aaf4b1f4..bc81f8f25 100644
--- a/unix/vncserver/selinux/vncsession.fc
+++ b/unix/vncserver/selinux/vncsession.fc
@@ -18,7 +18,7 @@
#
HOME_DIR/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
-HOME_ROOT/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
+/root/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0)
/usr/sbin/vncsession -- gen_context(system_u:object_r:vnc_session_exec_t,s0)
/usr/libexec/vncsession-start -- gen_context(system_u:object_r:vnc_session_exec_t,s0)

@ -0,0 +1,28 @@
From 774c6bcf33b5c9b94c1ff12895775e77c555decc Mon Sep 17 00:00:00 2001
From: Pierre Ossman <ossman@cendio.se>
Date: Thu, 9 Feb 2023 11:30:37 +0100
Subject: [PATCH] Sanity check when cleaning up keymap changes
Make sure we don't send a bogus request to the X server in the (common)
case that we don't actually have anything to restore.
(cherry picked from commit 1e3484f2017f038dd5149cd50741feaf39a680e4)
---
unix/x0vncserver/XDesktop.cxx | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index d5c6b2db9..f9c810968 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -481,6 +481,10 @@ void XDesktop::deleteAddedKeysyms(Display* dpy) {
}
}
+ // Did we actually find something to remove?
+ if (highestKeyCode < lowestKeyCode)
+ return;
+
changes.changed |= XkbKeySymsMask;
changes.first_key_sym = lowestKeyCode;
changes.num_key_syms = highestKeyCode - lowestKeyCode + 1;

@ -0,0 +1,31 @@
From 717d787de8f913070446444e37d552b51f05515e Mon Sep 17 00:00:00 2001
From: Zdenek Pytela <zpytela@redhat.com>
Date: Mon, 16 Jan 2023 12:35:40 +0100
Subject: [PATCH] SELinux: Allow vncsession create ~/.vnc directory
Addresses the following AVC denial:
type=PROCTITLE msg=audit(01/12/2023 02:58:12.648:696) : proctitle=/usr/sbin/vncsession fedora :1
type=PATH msg=audit(01/12/2023 02:58:12.648:696) : item=1 name=/home/fedora/.vnc nametype=CREATE cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(01/12/2023 02:58:12.648:696) : item=0 name=/home/fedora/ inode=262145 dev=fc:02 mode=dir,700 ouid=fedora ogid=fedora rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(01/12/2023 02:58:12.648:696) : cwd=/home/fedora
type=SYSCALL msg=audit(01/12/2023 02:58:12.648:696) : arch=x86_64 syscall=mkdir success=no exit=EACCES(Permission denied) a0=0x7fff47d52540 a1=0755 a2=0x0 a3=0x0 items=2 ppid=2869 pid=2880 auid=fedora uid=fedora gid=fedora euid=fedora suid=fedora fsuid=fedora egid=fedora sgid=fedora fsgid=fedora tty=(none) ses=8 comm=vncsession exe=/usr/sbin/vncsession subj=system_u:system_r:vnc_session_t:s0 key=(null)
type=AVC msg=audit(01/12/2023 02:58:12.648:696) : avc: denied { create } for pid=2880 comm=vncsession name=.vnc scontext=system_u:system_r:vnc_session_t:s0 tcontext=system_u:object_r:vnc_home_t:s0 tclass=dir permissive=0
Resolves: rhbz#2143704
---
unix/vncserver/selinux/vncsession.te | 1 +
1 file changed, 1 insertion(+)
diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te
index fb966c14b..680be8ea1 100644
--- a/unix/vncserver/selinux/vncsession.te
+++ b/unix/vncserver/selinux/vncsession.te
@@ -37,6 +37,7 @@ allow vnc_session_t self:fifo_file rw_fifo_file_perms;
allow vnc_session_t vnc_session_var_run_t:file manage_file_perms;
files_pid_filetrans(vnc_session_t, vnc_session_var_run_t, file)
+create_dirs_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_fifo_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_sock_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)

@ -0,0 +1,81 @@
From d2d52704624ce841f4a392fccd82079d87ff13b6 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Thu, 11 Nov 2021 13:52:41 +0100
Subject: [PATCH] SELinux: restore SELinux context in case of different
policies
---
CMakeLists.txt | 13 +++++++++++++
unix/vncserver/CMakeLists.txt | 2 +-
unix/vncserver/vncsession.c | 16 ++++++++++++++++
3 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50247c7da..1708eb3d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -268,6 +268,19 @@ if(UNIX AND NOT APPLE)
endif()
endif()
+# Check for SELinux library
+if(UNIX AND NOT APPLE)
+ check_include_files(selinux/selinux.h HAVE_SELINUX_H)
+ if(HAVE_SELINUX_H)
+ set(CMAKE_REQUIRED_LIBRARIES -lselinux)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ set(SELINUX_LIBS selinux)
+ add_definitions("-DHAVE_SELINUX")
+ else()
+ message(WARNING "Could not find SELinux development files")
+ endif()
+endif()
+
# Generate config.h and make sure the source finds it
configure_file(config.h.in config.h)
add_definitions(-DHAVE_CONFIG_H)
diff --git a/unix/vncserver/CMakeLists.txt b/unix/vncserver/CMakeLists.txt
index f65ccc7db..ae69dc098 100644
--- a/unix/vncserver/CMakeLists.txt
+++ b/unix/vncserver/CMakeLists.txt
@@ -1,5 +1,5 @@
add_executable(vncsession vncsession.c)
-target_link_libraries(vncsession ${PAM_LIBS})
+target_link_libraries(vncsession ${PAM_LIBS} ${SELINUX_LIBS})
configure_file(vncserver@.service.in vncserver@.service @ONLY)
configure_file(vncsession-start.in vncsession-start @ONLY)
diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c
index 3573e5e9b..f6d2fd59e 100644
--- a/unix/vncserver/vncsession.c
+++ b/unix/vncserver/vncsession.c
@@ -37,6 +37,11 @@
#include <sys/types.h>
#include <sys/wait.h>
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/restorecon.h>
+#endif
+
extern char **environ;
// PAM service name
@@ -360,6 +365,17 @@ redir_stdio(const char *homedir, const char *display)
syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno));
_exit(EX_OSERR);
}
+
+#ifdef HAVE_SELINUX
+ int result;
+ if (selinux_file_context_verify(logfile, 0) == 0) {
+ result = selinux_restorecon(logfile, SELINUX_RESTORECON_RECURSE);
+
+ if (result < 0) {
+ syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", logfile, strerror(errno));
+ }
+ }
+#endif
}
hostlen = sysconf(_SC_HOST_NAME_MAX);

@ -0,0 +1,12 @@
diff --git a/unix/vncserver/vncserver-config-defaults b/unix/vncserver/vncserver-config-defaults
index 0c217bf..2889347 100644
--- a/unix/vncserver/vncserver-config-defaults
+++ b/unix/vncserver/vncserver-config-defaults
@@ -13,3 +13,7 @@
# geometry=2000x1200
# localhost
# alwaysshared
+
+# Default to GNOME session
+# Note: change this only when you know what are you doing
+session=gnome

@ -0,0 +1,113 @@
From 1919a8ab86c99b47ba86dc697abcdf3343b0aafa Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 1 Feb 2022 14:31:05 +0100
Subject: Add vncsession-restore script to restore SELinux context
The vncsession-restore script is used in the ExecStartPre option
for systemd service file in order to properly start the session
in case the policy is updated (e.g. after Tigervnc update).
diff --git a/unix/vncserver/CMakeLists.txt b/unix/vncserver/CMakeLists.txt
index ae69dc09..04eb6fc4 100644
--- a/unix/vncserver/CMakeLists.txt
+++ b/unix/vncserver/CMakeLists.txt
@@ -2,6 +2,7 @@ add_executable(vncsession vncsession.c)
target_link_libraries(vncsession ${PAM_LIBS} ${SELINUX_LIBS})
configure_file(vncserver@.service.in vncserver@.service @ONLY)
+configure_file(vncsession-restore.in vncsession-restore @ONLY)
configure_file(vncsession-start.in vncsession-start @ONLY)
configure_file(vncserver.in vncserver @ONLY)
configure_file(vncsession.man.in vncsession.man @ONLY)
@@ -20,4 +21,5 @@ install(FILES HOWTO.md DESTINATION ${CMAKE_INSTALL_FULL_DOCDIR})
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})
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncsession-restore DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
endif()
diff --git a/unix/vncserver/vncserver@.service.in b/unix/vncserver/vncserver@.service.in
index 39f81b73..a83e05a3 100644
--- a/unix/vncserver/vncserver@.service.in
+++ b/unix/vncserver/vncserver@.service.in
@@ -35,6 +35,7 @@ After=syslog.target network.target
[Service]
Type=forking
+ExecStartPre=+@CMAKE_INSTALL_FULL_LIBEXECDIR@/vncsession-restore %i
ExecStart=@CMAKE_INSTALL_FULL_LIBEXECDIR@/vncsession-start %i
PIDFile=/run/vncsession-%i.pid
SELinuxContext=system_u:system_r:vnc_session_t:s0
diff --git a/unix/vncserver/vncsession-restore.in b/unix/vncserver/vncsession-restore.in
new file mode 100644
index 00000000..d3abc57d
--- /dev/null
+++ b/unix/vncserver/vncsession-restore.in
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# Copyright 2022 Jan Grulich <jgrulich@redhat.com>
+#
+# 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- | sed 's/ *$//g'`
+
+if [ -z "${USER}" ]; then
+ echo "No user configured for display ${DISPLAY}" >&2
+ exit 1
+fi
+
+USER_HOMEDIR=`getent passwd ${USER} | cut -f6 -d:`
+
+if [ -z "${USER_HOMEDIR}" ]; then
+ echo "Failed to get home directory for ${USER}" >&2
+ exit 1
+fi
+
+if [ ! -d "${USER_HOMEDIR}/.vnc" ]; then
+ exit 0
+fi
+
+MATCHPATHCON=`which matchpathcon`
+
+if [ $? -eq 0 ]; then
+ ${MATCHPATHCON} -V "${USER_HOMEDIR}/.vnc" &>/dev/null
+ if [ $? -eq 0 ]; then
+ exit 0
+ fi
+fi
+
+RESTORECON=`which restorecon`
+
+if [ $? -eq 0 ]; then
+ exec "${RESTORECON}" -R "${USER_HOMEDIR}/.vnc" >&2
+ return $?
+fi

@ -0,0 +1,91 @@
diff -up xserver/configure.ac.xserver116-rebased xserver/configure.ac
--- xserver/configure.ac.xserver116-rebased 2016-09-29 13:14:45.595441590 +0200
+++ xserver/configure.ac 2016-09-29 13:14:45.631442006 +0200
@@ -74,6 +74,7 @@ dnl forcing an entire recompile.x
AC_CONFIG_HEADERS(include/version-config.h)
AM_PROG_AS
+AC_PROG_CXX
AC_PROG_LN_S
LT_PREREQ([2.2])
LT_INIT([disable-static win32-dll])
@@ -1863,6 +1864,10 @@ if test "x$XVFB" = xyes; then
AC_SUBST([XVFB_SYS_LIBS])
fi
+dnl Xvnc DDX
+AC_SUBST([XVNC_CPPFLAGS], ["-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS"])
+AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"])
+AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"])
dnl Xnest DDX
@@ -1898,6 +1903,8 @@ if test "x$XORG" = xauto; then
fi
AC_MSG_RESULT([$XORG])
+AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
+
if test "x$XORG" = xyes; then
XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common'
XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os'
@@ -2116,7 +2123,6 @@ if test "x$XORG" = xyes; then
AC_DEFINE(XORG_SERVER, 1, [Building Xorg server])
AC_DEFINE(XORGSERVER, 1, [Building Xorg server])
AC_DEFINE(XFree86Server, 1, [Building XFree86 server])
- AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs])
AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions])
AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server])
@@ -2691,6 +2697,7 @@ hw/dmx/Makefile
hw/dmx/man/Makefile
hw/vfb/Makefile
hw/vfb/man/Makefile
+hw/vnc/Makefile
hw/xnest/Makefile
hw/xnest/man/Makefile
hw/xwin/Makefile
diff -up xserver/hw/Makefile.am.xserver116-rebased xserver/hw/Makefile.am
--- xserver/hw/Makefile.am.xserver116-rebased 2016-09-29 13:14:45.601441659 +0200
+++ xserver/hw/Makefile.am 2016-09-29 13:14:45.631442006 +0200
@@ -38,7 +38,8 @@ SUBDIRS = \
$(DMX_SUBDIRS) \
$(KDRIVE_SUBDIRS) \
$(XQUARTZ_SUBDIRS) \
- $(XWAYLAND_SUBDIRS)
+ $(XWAYLAND_SUBDIRS) \
+ vnc
DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
diff --git xserver/mi/miinitext.c xserver/mi/miinitext.c
index 5596e21..003fc3c 100644
--- xserver/mi/miinitext.c
+++ xserver/mi/miinitext.c
@@ -107,8 +107,15 @@ SOFTWARE.
#include "os.h"
#include "globals.h"
+#ifdef TIGERVNC
+extern void vncExtensionInit(INITARGS);
+#endif
+
/* List of built-in (statically linked) extensions */
static const ExtensionModule staticExtensions[] = {
+#ifdef TIGERVNC
+ {vncExtensionInit, "VNC-EXTENSION", NULL},
+#endif
{GEExtensionInit, "Generic Event Extension", &noGEExtension},
{ShapeExtensionInit, "SHAPE", NULL},
#ifdef MITSHM
--- xserver/include/os.h~ 2016-10-03 09:07:29.000000000 +0200
+++ xserver/include/os.h 2016-10-03 14:13:00.013654506 +0200
@@ -621,7 +621,7 @@
extern _X_EXPORT void
LogClose(enum ExitCode error);
extern _X_EXPORT Bool
-LogSetParameter(LogParameter param, int value);
+LogSetParameter(enum _LogParameter param, int value);
extern _X_EXPORT void
LogVWrite(int verb, const char *f, va_list args)
_X_ATTRIBUTE_PRINTF(2, 0);

@ -0,0 +1,897 @@
#!/usr/bin/perl
#
# 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.
#
# First make sure we're operating in a sane environment.
$exedir = "";
$slashndx = rindex($0, "/");
if($slashndx>=0) {
$exedir = substr($0, 0, $slashndx+1);
}
&SanityCheck();
&NotifyAboutDeprecation();
#
# Global variables. You may want to configure some of these for
# your site
#
$geometry = "1024x768";
#$depth = 16;
$vncUserDir = "$ENV{HOME}/.vnc";
$vncUserConfig = "$vncUserDir/config";
$vncSystemConfigDir = "/etc/tigervnc";
$vncSystemConfigDefaultsFile = "$vncSystemConfigDir/vncserver-config-defaults";
$vncSystemConfigMandatoryFile = "$vncSystemConfigDir/vncserver-config-mandatory";
$skipxstartup = 0;
$xauthorityFile = "$ENV{XAUTHORITY}" || "$ENV{HOME}/.Xauthority";
$xstartupFile = $vncUserDir . "/xstartup";
$defaultXStartup
= ("#!/bin/sh\n\n".
"unset SESSION_MANAGER\n".
"unset DBUS_SESSION_BUS_ADDRESS\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".
"## in this file. See the following manpages for more: vncserver(1) Xvnc(1).\n".
"## Several common ones are shown below. Uncomment and modify to your liking.\n".
"##\n".
"# securitytypes=vncauth,tlsvnc\n".
"# desktop=sandbox\n".
"# geometry=2000x1200\n".
"# localhost\n".
"# alwaysshared\n");
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;
}
# Check command line options
&ParseOptions("-geometry",1,"-depth",1,"-pixelformat",1,"-name",1,"-kill",1,
"-help",0,"-h",0,"--help",0,"-fp",1,"-list",0,"-fg",0,"-autokill",0,"-noxstartup",0,"-xstartup",1);
&Usage() if ($opt{'-help'} || $opt{'-h'} || $opt{'--help'});
&Kill() if ($opt{'-kill'});
&List() if ($opt{'-list'});
# Uncomment this line if you want default geometry, depth and pixelformat
# to match the current X display:
# &GetXDisplayDefaults();
if ($opt{'-geometry'}) {
$geometry = $opt{'-geometry'};
}
if ($opt{'-depth'}) {
$depth = $opt{'-depth'};
$pixelformat = "";
}
if ($opt{'-pixelformat'}) {
$pixelformat = $opt{'-pixelformat'};
}
if ($opt{'-noxstartup'}) {
$skipxstartup = 1;
}
if ($opt{'-xstartup'}) {
$xstartupFile = $opt{'-xstartup'};
}
if ($opt{'-fp'}) {
$fontPath = $opt{'-fp'};
$fpArgSpecified = 1;
}
&CheckGeometryAndDepth();
# Create the user's vnc directory if necessary.
if (!(-e $vncUserDir)) {
if (!mkdir($vncUserDir,0755)) {
die "$prog: Could not create $vncUserDir.\n";
}
}
# Find display number.
if ((@ARGV > 0) && ($ARGV[0] =~ /^:(\d+)$/)) {
$displayNumber = $1;
shift(@ARGV);
if (!&CheckDisplayNumber($displayNumber)) {
warn "A VNC server is already running as :$displayNumber\n";
$displayNumber = &GetDisplayNumber();
}
} elsif ((@ARGV > 0) && ($ARGV[0] !~ /^-/) && ($ARGV[0] !~ /^\+/)) {
&Usage();
} else {
$displayNumber = &GetDisplayNumber();
}
$vncPort = 5900 + $displayNumber;
if ($opt{'-name'}) {
$desktopName = $opt{'-name'};
} else {
$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} = &quotedString($desktopName);
$default_opts{auth} = &quotedString($xauthorityFile);
$default_opts{geometry} = $geometry if ($geometry);
$default_opts{depth} = $depth if ($depth);
$default_opts{pixelformat} = $pixelformat if ($pixelformat);
$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, prompt the user to
# create a VNC password if they don't already have one.
#
$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;
}
}
}
# ...and finally we check CLI args, which in the case of the topic at
# hand (VNC auth or not), override anything found in configuration files
# (even so-called "mandatory" settings).
for ($i = 0; $i < @ARGV; ++$i) {
# -SecurityTypes can be followed by a space or "="
my @splitargs = split('=', $ARGV[$i]);
if (@splitargs <= 1 && $i < @ARGV - 1) {
push(@splitargs, $ARGV[$i + 1]);
}
if (lc(@splitargs[0]) eq "-securitytypes") {
if (@splitargs > 1) {
$securityTypeArgSpecified = 1;
}
foreach $arg2 (split(',', @splitargs[1])) {
if (grep {$_ eq lc($arg2)} @vncAuthStrings) {
$vncAuthEnabled = 1;
}
}
}
if ((lc(@splitargs[0]) eq "-password")
|| (lc(@splitargs[0]) eq "-passwordfile"
|| (lc(@splitargs[0]) eq "-rfbauth"))) {
$passwordArgSpecified = 1;
}
}
if ((!$securityTypeArgSpecified || $vncAuthEnabled) && !$passwordArgSpecified) {
($z,$z,$mode) = stat("$vncUserDir/passwd");
if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
warn "\nYou will require a password to access your desktops.\n\n";
system($exedir."vncpasswd -q $vncUserDir/passwd");
if (($? >> 8) != 0) {
exit 1;
}
}
}
$desktopLog = "$vncUserDir/$host:$displayNumber.log";
unlink($desktopLog);
# 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);
# Now start the X VNC Server
# We build up our Xvnc command with options
$cmd = $exedir."Xvnc :$displayNumber";
foreach my $k (sort keys %config) {
$cmd .= " -$k $config{$k}";
delete $default_opts{$k}; # file options take precedence
}
foreach my $k (sort keys %default_opts) {
$cmd .= " -$k $default_opts{$k}";
}
# Add color database stuff here, e.g.:
# $cmd .= " -co /usr/lib/X11/rgb";
foreach $arg (@ARGV) {
$cmd .= " " . &quotedString($arg);
}
$cmd .= " >> " . &quotedString($desktopLog) . " 2>&1";
# Run $cmd and record the process ID.
$pidFile = "$vncUserDir/$host:$displayNumber.pid";
system("$cmd & echo \$! >$pidFile");
# Give Xvnc a chance to start up
sleep(3);
if ($fontPath ne $defFontPath) {
unless (kill 0, `cat $pidFile`) {
if ($fpArgSpecified) {
warn "\nWARNING: The first attempt to start Xvnc failed, probably because the font\n";
warn "path you specified using the -fp argument is incorrect. Attempting to\n";
warn "determine an appropriate font path for this system and restart Xvnc using\n";
warn "that font path ...\n";
} else {
warn "\nWARNING: The first attempt to start Xvnc failed, possibly because the font\n";
warn "catalog is not properly configured. Attempting to determine an appropriate\n";
warn "font path for this system and restart Xvnc using that font path ...\n";
}
$cmd =~ s@-fp [^ ]+@@;
$cmd .= " -fp $defFontPath" if ($defFontPath);
system("$cmd & echo \$! >$pidFile");
sleep(3);
}
}
unless (kill 0, `cat $pidFile`) {
warn "Could not start Xvnc.\n\n";
unlink $pidFile;
open(LOG, "<$desktopLog");
while (<LOG>) { print; }
close(LOG);
die "\n";
}
warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
# Create the user's xstartup script if necessary.
if (! $skipxstartup) {
if (!(-e "$xstartupFile")) {
warn "Creating default startup script $xstartupFile\n";
open(XSTARTUP, ">$xstartupFile");
print XSTARTUP $defaultXStartup;
close(XSTARTUP);
chmod 0755, "$xstartupFile";
}
}
# Create the user's config file if necessary.
if (!(-e "$vncUserDir/config")) {
warn "Creating default config $vncUserDir/config\n";
open(VNCUSERCONFIG, ">$vncUserDir/config");
print VNCUSERCONFIG $defaultConfig;
close(VNCUSERCONFIG);
chmod 0644, "$vncUserDir/config";
}
# Run the X startup script.
if (! $skipxstartup) {
warn "Starting applications specified in $xstartupFile\n";
}
warn "Log file is $desktopLog\n\n";
# If the unix domain socket exists then use that (DISPLAY=:n) otherwise use
# TCP (DISPLAY=host:n)
if (-e "/tmp/.X11-unix/X$displayNumber" ||
-e "/usr/spool/sockets/X11/$displayNumber")
{
$ENV{DISPLAY}= ":$displayNumber";
} else {
$ENV{DISPLAY}= "$host:$displayNumber";
}
$ENV{VNCDESKTOP}= $desktopName;
if ($opt{'-fg'}) {
if (! $skipxstartup) {
system("$xstartupFile >> " . &quotedString($desktopLog) . " 2>&1");
}
if (kill 0, `cat $pidFile`) {
$opt{'-kill'} = ':'.$displayNumber;
&Kill();
}
} else {
if ($opt{'-autokill'}) {
if (! $skipxstartup) {
system("($xstartupFile; $0 -kill :$displayNumber) >> "
. &quotedString($desktopLog) . " 2>&1 &");
}
} else {
if (! $skipxstartup) {
system("$xstartupFile >> " . &quotedString($desktopLog)
. " 2>&1 &");
}
}
}
exit;
###############################################################################
# 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 ($k eq "session") {
next;
}
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);
}
}
}
#
# CheckGeometryAndDepth simply makes sure that the geometry and depth values
# are sensible.
#
sub CheckGeometryAndDepth
{
if ($geometry =~ /^(\d+)x(\d+)$/) {
$width = $1; $height = $2;
if (($width<1) || ($height<1)) {
die "$prog: geometry $geometry is invalid\n";
}
$geometry = "${width}x$height";
} else {
die "$prog: geometry $geometry is invalid\n";
}
if ($depth && (($depth < 8) || ($depth > 32))) {
die "Depth must be between 8 and 32\n";
}
}
#
# GetDisplayNumber gets the lowest available display number. 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 GetDisplayNumber
{
foreach $n (1..99) {
if (&CheckDisplayNumber($n)) {
return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
}
}
die "$prog: no free display number on $host.\n";
}
#
# 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;
}
#
# GetXDisplayDefaults uses xdpyinfo to find out the geometry, depth and pixel
# format of the current X display being used. If successful, it sets the
# options as appropriate so that the X VNC server will use the same settings
# (minus an allowance for window manager decorations on the geometry). Using
# the same depth and pixel format means that the VNC server won't have to
# translate pixels when the desktop is being viewed on this X display (for
# TrueColor displays anyway).
#
sub GetXDisplayDefaults
{
local (@lines, @matchlines, $width, $height, $defaultVisualId, $i,
$red, $green, $blue);
$wmDecorationWidth = 4; # a guess at typical size for window manager
$wmDecorationHeight = 24; # decoration size
return if (!defined($ENV{DISPLAY}));
@lines = `xdpyinfo 2>/dev/null`;
return if ($? != 0);
@matchlines = grep(/dimensions/, @lines);
if (@matchlines) {
($width, $height) = ($matchlines[0] =~ /(\d+)x(\d+) pixels/);
$width -= $wmDecorationWidth;
$height -= $wmDecorationHeight;
$geometry = "${width}x$height";
}
@matchlines = grep(/default visual id/, @lines);
if (@matchlines) {
($defaultVisualId) = ($matchlines[0] =~ /id:\s+(\S+)/);
for ($i = 0; $i < @lines; $i++) {
if ($lines[$i] =~ /^\s*visual id:\s+$defaultVisualId$/) {
if (($lines[$i+1] !~ /TrueColor/) ||
($lines[$i+2] !~ /depth/) ||
($lines[$i+4] !~ /red, green, blue masks/))
{
return;
}
last;
}
}
return if ($i >= @lines);
($depth) = ($lines[$i+2] =~ /depth:\s+(\d+)/);
($red,$green,$blue)
= ($lines[$i+4]
=~ /masks:\s+0x([0-9a-f]+), 0x([0-9a-f]+), 0x([0-9a-f]+)/);
$red = hex($red);
$green = hex($green);
$blue = hex($blue);
if ($red > $blue) {
$red = int(log($red) / log(2)) - int(log($green) / log(2));
$green = int(log($green) / log(2)) - int(log($blue) / log(2));
$blue = int(log($blue) / log(2)) + 1;
$pixelformat = "rgb$red$green$blue";
} else {
$blue = int(log($blue) / log(2)) - int(log($green) / log(2));
$green = int(log($green) / log(2)) - int(log($red) / log(2));
$red = int(log($red) / log(2)) + 1;
$pixelformat = "bgr$blue$green$red";
}
}
}
#
# quotedString returns a string which yields the original string when parsed
# by a shell.
#
sub quotedString
{
local ($in) = @_;
$in =~ s/\'/\'\"\'\"\'/g;
return "'$in'";
}
#
# removeSlashes turns slashes into underscores for use as a file name.
#
sub removeSlashes
{
local ($in) = @_;
$in =~ s|/|_|g;
return "$in";
}
#
# Usage
#
sub Usage
{
die("\nusage: $prog [:<number>] [-name <desktop-name>] [-depth <depth>]\n".
" [-geometry <width>x<height>]\n".
" [-pixelformat rgbNNN|bgrNNN]\n".
" [-fp <font-path>]\n".
" [-cc <visual>]\n".
" [-fg]\n".
" [-autokill]\n".
" [-noxstartup]\n".
" [-xstartup <file>]\n".
" <Xvnc-options>...\n\n".
" $prog -kill <X-display>\n\n".
" $prog -list\n\n");
}
#
# List
#
sub List
{
opendir(dir, $vncUserDir);
my @filelist = readdir(dir);
closedir(dir);
print "\nTigerVNC server sessions:\n\n";
print "X DISPLAY #\tPROCESS ID\n";
foreach my $file (@filelist) {
if ($file =~ /$host:(\d+)$\.pid/) {
chop($tmp_pid = `cat $vncUserDir/$file`);
if (kill 0, $tmp_pid) {
print ":".$1."\t\t".`cat $vncUserDir/$file`;
} else {
unlink ($vncUserDir . "/" . $file);
}
}
}
exit;
}
#
# Kill
#
sub Kill
{
$opt{'-kill'} =~ s/(:\d+)\.\d+$/$1/; # e.g. turn :1.0 into :1
if ($opt{'-kill'} =~ /^:\d+$/) {
$pidFile = "$vncUserDir/$host$opt{'-kill'}.pid";
} else {
if ($opt{'-kill'} !~ /^$host:/) {
die "\nCan't tell if $opt{'-kill'} is on $host\n".
"Use -kill :<number> instead\n\n";
}
$pidFile = "$vncUserDir/$opt{'-kill'}.pid";
}
if (! -r $pidFile) {
die "\nCan't find file $pidFile\n".
"You'll have to kill the Xvnc process manually\n\n";
}
$SIG{'HUP'} = 'IGNORE';
chop($pid = `cat $pidFile`);
warn "Killing Xvnc process ID $pid\n";
if (kill 0, $pid) {
system("kill $pid");
sleep(1);
if (kill 0, $pid) {
print "Xvnc seems to be deadlocked. Kill the process manually and then re-run\n";
print " ".$0." -kill ".$opt{'-kill'}."\n";
print "to clean up the socket files.\n";
exit
}
} else {
warn "Xvnc process ID $pid already killed\n";
$opt{'-kill'} =~ s/://;
if (-e "/tmp/.X11-unix/X$opt{'-kill'}") {
print "Xvnc did not appear to shut down cleanly.";
print " Removing /tmp/.X11-unix/X$opt{'-kill'}\n";
unlink "/tmp/.X11-unix/X$opt{'-kill'}";
}
if (-e "/tmp/.X$opt{'-kill'}-lock") {
print "Xvnc did not appear to shut down cleanly.";
print " Removing /tmp/.X$opt{'-kill'}-lock\n";
unlink "/tmp/.X$opt{'-kill'}-lock";
}
}
unlink $pidFile;
exit;
}
#
# ParseOptions takes a list of possible options and a boolean indicating
# whether the option has a value following, and sets up an associative array
# %opt of the values of the options given on the command line. It removes all
# the arguments it uses from @ARGV and returns them in @optArgs.
#
sub ParseOptions
{
local (@optval) = @_;
local ($opt, @opts, %valFollows, @newargs);
while (@optval) {
$opt = shift(@optval);
push(@opts,$opt);
$valFollows{$opt} = shift(@optval);
}
@optArgs = ();
%opt = ();
arg: while (defined($arg = shift(@ARGV))) {
foreach $opt (@opts) {
if ($arg eq $opt) {
push(@optArgs, $arg);
if ($valFollows{$opt}) {
if (@ARGV == 0) {
&Usage();
}
$opt{$opt} = shift(@ARGV);
push(@optArgs, $opt{$opt});
} else {
$opt{$opt} = 1;
}
next arg;
}
}
push(@newargs,$arg);
}
@ARGV = @newargs;
}
# 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") {
for (split(/:/,$ENV{PATH})) {
if (-x "$_/$cmd") {
next cmd;
}
}
die "$prog: couldn't find \"$cmd\" on your PATH.\n";
}
if($exedir eq "") {
cmd2:
foreach $cmd ("Xvnc","vncpasswd") {
for (split(/:/,$ENV{PATH})) {
if (-x "$_/$cmd") {
next cmd2;
}
}
die "$prog: couldn't find \"$cmd\" on your PATH.\n";
}
}
else {
cmd3:
foreach $cmd ($exedir."Xvnc",$exedir."vncpasswd") {
for (split(/:/,$ENV{PATH})) {
if (-x "$cmd") {
next cmd3;
}
}
die "$prog: couldn't find \"$cmd\".\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;
}
}
sub NotifyAboutDeprecation
{
warn "\nWARNING: vncserver has been replaced by a systemd unit and is now considered deprecated and removed in upstream.\n";
warn "Please read /usr/share/doc/tigervnc/HOWTO.md for more information.\n";
}

@ -0,0 +1,38 @@
# The vncserver service unit file
#
# Quick HowTo:
# 1. Copy this file to /etc/systemd/system/xvnc@.service
# 2. Copy xvnc.socket to /etc/systemd/system/xvnc.socket
# 3. Run `systemctl daemon-reload`
# 4. Run `systemctl enable xvnc.socket`
#
# 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=XVNC Per-Connection Daemon
[Service]
ExecStart=-/usr/bin/Xvnc -inetd -query localhost -geometry 1024x768 -depth 24 -once -SecurityTypes=None
User=nobody
StandardInput=socket
StandardError=syslog

@ -0,0 +1,9 @@
[Unit]
Description=XVNC Server
[Socket]
ListenStream=5900
Accept=yes
[Install]
WantedBy=sockets.target

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save