diff --git a/CVE-2020-26117.patch b/CVE-2020-26117.patch deleted file mode 100644 index 60c9932edd0d8009b53f9b1c2d9e519f6c7610c7..0000000000000000000000000000000000000000 --- a/CVE-2020-26117.patch +++ /dev/null @@ -1,460 +0,0 @@ -Description: Properly store certificate exceptions in native and java VNC viewer. - They stored the certificates as authorities, meaning that the owner of a - certificate could impersonate any server after a client had added an exception. -Author: Pierre Ossman and Brian P. Hinz -Abstract: - Properly store certificate exceptions - . - . git commit b30f10c681ec87720cff85d490f67098568a9cba - . - The previous method stored the certificates as authorities, meaning that - the owner of that certificate could impersonate any server it wanted - after a client had added an exception. - . - Handle this more properly by only storing exceptions for specific - hostname/certificate combinations, the same way browsers or SSH does - things. - . - . git commit f029745f63ac7d22fb91639b2cb5b3ab56134d6e - . - Like the native viewer, the Java viewer didn't store certificate - exceptions properly. Whilst not as bad as the native viewer, it still - failed to check that a stored certificate wouldn't be maliciously used - for another server. In practice this can in most cases be used to - impersonate another server. - . - Handle this like the native viewer by storing exceptions for a specific - hostname/certificate combination. - . - This issue is CVE-2020-26117. - -Index: pkg-tigervnc/common/rfb/CSecurityTLS.cxx -=================================================================== ---- pkg-tigervnc.orig/common/rfb/CSecurityTLS.cxx -+++ pkg-tigervnc/common/rfb/CSecurityTLS.cxx -@@ -250,22 +250,6 @@ void CSecurityTLS::setParam() - if (*cafile && gnutls_certificate_set_x509_trust_file(cert_cred,cafile,GNUTLS_X509_FMT_PEM) < 0) - throw AuthFailureException("load of CA cert failed"); - -- /* Load previously saved certs */ -- char *homeDir = NULL; -- int err; -- if (getvnchomedir(&homeDir) == -1) -- vlog.error("Could not obtain VNC home directory path"); -- else { -- CharArray caSave(strlen(homeDir) + 19 + 1); -- sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir); -- delete [] homeDir; -- -- err = gnutls_certificate_set_x509_trust_file(cert_cred, caSave.buf, -- GNUTLS_X509_FMT_PEM); -- if (err < 0) -- vlog.debug("Failed to load saved server certificates from %s", caSave.buf); -- } -- - if (*crlfile && gnutls_certificate_set_x509_crl_file(cert_cred,crlfile,GNUTLS_X509_FMT_PEM) < 0) - throw AuthFailureException("load of CRL failed"); - -@@ -290,7 +274,10 @@ void CSecurityTLS::checkSession() - const gnutls_datum_t *cert_list; - unsigned int cert_list_size = 0; - int err; -+ -+ char *homeDir; - gnutls_datum_t info; -+ size_t len; - - if (anon) - return; -@@ -333,13 +320,13 @@ void CSecurityTLS::checkSession() - throw AuthFailureException("decoding of certificate failed"); - - if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { -- char buf[255]; -+ CharArray text; - vlog.debug("hostname mismatch"); -- snprintf(buf, sizeof(buf), "Hostname (%s) does not match any certificate, " -- "do you want to continue?", client->getServerName()); -- buf[sizeof(buf) - 1] = '\0'; -- if (!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf)) -- throw AuthFailureException("hostname mismatch"); -+ text.format("Hostname (%s) does not match the server certificate, " -+ "do you want to continue?", client->getServerName()); -+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, -+ "Certificate hostname mismatch", text.buf)) -+ throw AuthFailureException("Certificate hostname mismatch"); - } - - if (status == 0) { -@@ -366,87 +353,80 @@ void CSecurityTLS::checkSession() - - vlog.debug("Saved server certificates don't match"); - -- if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) { -- /* -- * GNUTLS doesn't correctly export gnutls_free symbol which is -- * a function pointer. Linking with Visual Studio 2008 Express will -- * fail when you call gnutls_free(). -- */ --#if WIN32 -- free(info.data); --#else -- gnutls_free(info.data); --#endif -- throw AuthFailureException("Could not find certificate to display"); -+ homeDir = NULL; -+ if (getvnchomedir(&homeDir) == -1) { -+ throw AuthFailureException("Could not obtain VNC home directory " -+ "path for known hosts storage"); -+ } -+ -+ CharArray dbPath(strlen(homeDir) + 16 + 1); -+ sprintf(dbPath.buf, "%sx509_known_hosts", homeDir); -+ delete [] homeDir; -+ -+ err = gnutls_verify_stored_pubkey(dbPath.buf, NULL, -+ client->getServerName(), NULL, -+ GNUTLS_CRT_X509, &cert_list[0], 0); -+ -+ /* Previously known? */ -+ if (err == GNUTLS_E_SUCCESS) { -+ vlog.debug("Server certificate found in known hosts file"); -+ gnutls_x509_crt_deinit(crt); -+ return; - } - -- size_t out_size = 0; -- char *out_buf = NULL; -- char *certinfo = NULL; -- int len = 0; -- -- vlog.debug("certificate issuer unknown"); -- -- len = snprintf(NULL, 0, "This certificate has been signed by an unknown " -- "authority:\n\n%s\n\nDo you want to save it and " -- "continue?\n ", info.data); -- if (len < 0) -- throw AuthFailureException("certificate decoding error"); -- -- vlog.debug("%s", info.data); -- -- certinfo = new char[len]; -- if (certinfo == NULL) -- throw AuthFailureException("Out of memory"); -- -- snprintf(certinfo, len, "This certificate has been signed by an unknown " -- "authority:\n\n%s\n\nDo you want to save it and " -- "continue? ", info.data); -- -- for (int i = 0; i < len - 1; i++) -- if (certinfo[i] == ',' && certinfo[i + 1] == ' ') -- certinfo[i] = '\n'; -- -- if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown", -- certinfo)) { -- delete [] certinfo; -- throw AuthFailureException("certificate issuer unknown"); -- } -- -- delete [] certinfo; -- -- if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size) -- == GNUTLS_E_SHORT_MEMORY_BUFFER) -- throw AuthFailureException("Out of memory"); -- -- // Save cert -- out_buf = new char[out_size]; -- if (out_buf == NULL) -- throw AuthFailureException("Out of memory"); -- -- if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size) < 0) -- throw AuthFailureException("certificate issuer unknown, and certificate " -- "export failed"); -- -- char *homeDir = NULL; -- if (getvnchomedir(&homeDir) == -1) -- vlog.error("Could not obtain VNC home directory path"); -- else { -- FILE *f; -- CharArray caSave(strlen(homeDir) + 1 + 19); -- sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir); -- delete [] homeDir; -- f = fopen(caSave.buf, "a+"); -- if (!f) -- msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed", -- "Could not save the certificate"); -- else { -- fprintf(f, "%s\n", out_buf); -- fclose(f); -- } -+ if ((err != GNUTLS_E_NO_CERTIFICATE_FOUND) && -+ (err != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { -+ throw AuthFailureException("Could not load known hosts database"); - } - -- delete [] out_buf; -+ if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) -+ throw AuthFailureException("Could not find certificate to display"); -+ -+ len = strlen((char*)info.data); -+ for (size_t i = 0; i < len - 1; i++) { -+ if (info.data[i] == ',' && info.data[i + 1] == ' ') -+ info.data[i] = '\n'; -+ } -+ -+ /* New host */ -+ if (err == GNUTLS_E_NO_CERTIFICATE_FOUND) { -+ CharArray text; -+ -+ vlog.debug("Server host not previously known"); -+ vlog.debug("%s", info.data); -+ -+ text.format("This certificate has been signed by an unknown " -+ "authority:\n\n%s\n\nSomeone could be trying to " -+ "impersonate the site and you should not " -+ "continue.\n\nDo you want to make an exception " -+ "for this server?", info.data); -+ -+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, -+ "Unknown certificate issuer", -+ text.buf)) -+ throw AuthFailureException("Unknown certificate issuer"); -+ } else if (err == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { -+ CharArray text; -+ -+ vlog.debug("Server host key mismatch"); -+ vlog.debug("%s", info.data); -+ -+ text.format("This host is previously known with a different " -+ "certificate, and the new certificate has been " -+ "signed by an unknown authority:\n\n%s\n\nSomeone " -+ "could be trying to impersonate the site and you " -+ "should not continue.\n\nDo you want to make an " -+ "exception for this server?", info.data); -+ -+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, -+ "Unexpected server certificate", -+ text.buf)) -+ throw AuthFailureException("Unexpected server certificate"); -+ } -+ -+ if (gnutls_store_pubkey(dbPath.buf, NULL, client->getServerName(), -+ NULL, GNUTLS_CRT_X509, &cert_list[0], 0, 0)) -+ vlog.error("Failed to store server certificate to known hosts database"); - - gnutls_x509_crt_deinit(crt); - /* -Index: pkg-tigervnc/java/com/tigervnc/rfb/CSecurityTLS.java -=================================================================== ---- pkg-tigervnc.orig/java/com/tigervnc/rfb/CSecurityTLS.java -+++ pkg-tigervnc/java/com/tigervnc/rfb/CSecurityTLS.java -@@ -107,12 +107,6 @@ public class CSecurityTLS extends CSecur - X509CRL.setDefaultStr(getDefaultCRL()); - } - --// FIXME: --// Need to shutdown the connection cleanly -- --// FIXME? --// add a finalizer method that calls shutdown -- - public boolean processMsg(CConnection cc) { - is = (FdInStream)cc.getInStream(); - os = (FdOutStream)cc.getOutStream(); -@@ -269,8 +263,13 @@ public class CSecurityTLS extends CSecur - { - Collection certs = null; - X509Certificate cert = chain[0]; -+ String pk = -+ Base64.getEncoder().encodeToString(cert.getPublicKey().getEncoded()); - try { - cert.checkValidity(); -+ verifyHostname(cert); -+ } catch(CertificateParsingException e) { -+ throw new SystemException(e.getMessage()); - } catch(CertificateNotYetValidException e) { - throw new AuthFailureException("server certificate has not been activated"); - } catch(CertificateExpiredException e) { -@@ -279,73 +278,111 @@ public class CSecurityTLS extends CSecur - "do you want to continue?")) - throw new AuthFailureException("server certificate has expired"); - } -- String thumbprint = getThumbprint(cert); - File vncDir = new File(FileUtils.getVncHomeDir()); -- File certFile = new File(vncDir, "x509_savedcerts.pem"); -- CertificateFactory cf = CertificateFactory.getInstance("X.509"); -- if (vncDir.exists() && certFile.exists() && certFile.canRead()) { -- InputStream certStream = new MyFileInputStream(certFile); -- certs = cf.generateCertificates(certStream); -- for (Certificate c : certs) -- if (thumbprint.equals(getThumbprint((X509Certificate)c))) -- return; -- } -+ if (!vncDir.exists()) -+ throw new AuthFailureException("Could not obtain VNC home directory "+ -+ "path for known hosts storage"); -+ File dbPath = new File(vncDir, "x509_known_hosts"); -+ String info = -+ " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ -+ " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ -+ " Serial Number: "+cert.getSerialNumber()+"\n"+ -+ " Version: "+cert.getVersion()+"\n"+ -+ " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ -+ " Not Valid Before: "+cert.getNotBefore()+"\n"+ -+ " Not Valid After: "+cert.getNotAfter()+"\n"+ -+ " SHA-1 Fingerprint: "+getThumbprint(cert)+"\n"; - try { -- verifyHostname(cert); -+ if (dbPath.exists()) { -+ FileReader db = new FileReader(dbPath); -+ BufferedReader dbBuf = new BufferedReader(db); -+ String line; -+ String server = client.getServerName().toLowerCase(); -+ while ((line = dbBuf.readLine())!=null) { -+ String fields[] = line.split("\\|"); -+ if (fields.length==6) { -+ if (server.equals(fields[2]) && pk.equals(fields[5])) { -+ vlog.debug("Server certificate found in known hosts file"); -+ dbBuf.close(); -+ return; -+ } else if (server.equals(fields[2]) && !pk.equals(fields[5]) || -+ !server.equals(fields[2]) && pk.equals(fields[5])) { -+ throw new CertStoreException(); -+ } -+ } -+ } -+ dbBuf.close(); -+ } - tm.checkServerTrusted(chain, authType); -+ } catch (IOException e) { -+ throw new AuthFailureException("Could not load known hosts database"); -+ } catch (CertStoreException e) { -+ vlog.debug("Server host key mismatch"); -+ vlog.debug(info); -+ String text = -+ "This host is previously known with a different "+ -+ "certificate, and the new certificate has been "+ -+ "signed by an unknown authority\n"+ -+ "\n"+info+"\n"+ -+ "Someone could be trying to impersonate the site and you should not continue.\n"+ -+ "\n"+ -+ "Do you want to make an exception for this server?"; -+ if (!msg.showMsgBox(YES_NO_OPTION, "Unexpected certificate issuer", text)) -+ throw new AuthFailureException("Unexpected certificate issuer"); -+ store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); - } catch (java.lang.Exception e) { - if (e.getCause() instanceof CertPathBuilderException) { -- String certinfo = -+ vlog.debug("Server host not previously known"); -+ vlog.debug(info); -+ String text = - "This certificate has been signed by an unknown authority\n"+ -+ "\n"+info+"\n"+ -+ "Someone could be trying to impersonate the site and you should not continue.\n"+ - "\n"+ -- " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ -- " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ -- " Serial Number: "+cert.getSerialNumber()+"\n"+ -- " Version: "+cert.getVersion()+"\n"+ -- " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ -- " Not Valid Before: "+cert.getNotBefore()+"\n"+ -- " Not Valid After: "+cert.getNotAfter()+"\n"+ -- " SHA1 Fingerprint: "+getThumbprint(cert)+"\n"+ -- "\n"+ -- "Do you want to save it and continue?"; -- if (!msg.showMsgBox(YES_NO_OPTION, "certificate issuer unknown", -- certinfo)) { -- throw new AuthFailureException("certificate issuer unknown"); -- } -- if (certs == null || !certs.contains(cert)) { -- byte[] der = cert.getEncoded(); -- String pem = Base64.getEncoder().encodeToString(der); -- pem = pem.replaceAll("(.{64})", "$1\n"); -- FileWriter fw = null; -- try { -- if (!vncDir.exists()) -- vncDir.mkdir(); -- if (!certFile.exists() && !certFile.createNewFile()) { -- vlog.error("Certificate save failed."); -- } else { -- fw = new FileWriter(certFile.getAbsolutePath(), true); -- fw.write("-----BEGIN CERTIFICATE-----\n"); -- fw.write(pem+"\n"); -- fw.write("-----END CERTIFICATE-----\n"); -- } -- } catch (IOException ioe) { -- msg.showMsgBox(OK_OPTION, "certificate save failed", -- "Could not save the certificate"); -- } finally { -- try { -- if (fw != null) -- fw.close(); -- } catch(IOException ioe2) { -- throw new Exception(ioe2.getMessage()); -- } -- } -- } -+ "Do you want to make an exception for this server?"; -+ if (!msg.showMsgBox(YES_NO_OPTION, "Unknown certificate issuer", text)) -+ throw new AuthFailureException("Unknown certificate issuer"); -+ store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); - } else { - throw new SystemException(e.getMessage()); - } - } - } - -+ private void store_pubkey(File dbPath, String serverName, String pk) -+ { -+ ArrayList lines = new ArrayList(); -+ File vncDir = new File(FileUtils.getVncHomeDir()); -+ try { -+ if (dbPath.exists()) { -+ FileReader db = new FileReader(dbPath); -+ BufferedReader dbBuf = new BufferedReader(db); -+ String line; -+ while ((line = dbBuf.readLine())!=null) { -+ String fields[] = line.split("\\|"); -+ if (fields.length==6) -+ if (!serverName.equals(fields[2]) && !pk.equals(fields[5])) -+ lines.add(line); -+ } -+ dbBuf.close(); -+ } -+ } catch (IOException e) { -+ throw new AuthFailureException("Could not load known hosts database"); -+ } -+ try { -+ if (!dbPath.exists()) -+ dbPath.createNewFile(); -+ FileWriter fw = new FileWriter(dbPath.getAbsolutePath(), false); -+ Iterator i = lines.iterator(); -+ while (i.hasNext()) -+ fw.write((String)i.next()+"\n"); -+ fw.write("|g0|"+serverName+"|*|0|"+pk+"\n"); -+ fw.close(); -+ } catch (IOException e) { -+ vlog.error("Failed to store server certificate to known hosts database"); -+ } -+ } -+ - public X509Certificate[] getAcceptedIssuers () - { - return tm.getAcceptedIssuers(); -@@ -399,12 +436,13 @@ public class CSecurityTLS extends CSecur - } - Object[] answer = {"YES", "NO"}; - int ret = JOptionPane.showOptionDialog(null, -- "Hostname verification failed. Do you want to continue?", -- "Hostname Verification Failure", -+ "Hostname ("+client.getServerName()+") does not match the"+ -+ " server certificate, do you want to continue?", -+ "Certificate hostname mismatch", - JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, answer, answer[0]); - if (ret != JOptionPane.YES_OPTION) -- throw new WarningException("Hostname verification failed."); -+ throw new WarningException("Certificate hostname mismatch."); - } catch (CertificateParsingException e) { - throw new SystemException(e.getMessage()); - } catch (InvalidNameException e) { diff --git a/HOWTO.md b/HOWTO.md new file mode 100644 index 0000000000000000000000000000000000000000..52e47fc12b89e071c60c882bdf7ab22beddb3808 --- /dev/null +++ b/HOWTO.md @@ -0,0 +1,64 @@ +What has changed +The previous Tigervnc versions had a wrapper script called vncserver which could be run as a user manually to start Xvnc process. The usage was quite simple as you just run + +$ vncserver :x [vncserver options] [Xvnc options] +and that was it. While this was working just fine, there were issues when users wanted to start a Tigervnc server using systemd. For these reasons things were completely changed and there is now a new way how this all is supposed to work. + +# How to start Tigervnc server + +Add a user mapping +With this you can map a user to a particular port. The mapping should be done in /etc/tigervnc/vncserver.users configuration file. It should be pretty straightforward once you open the file as there are some examples, but basically the mapping is in form + +:x=user +For example you can have + +:1=test +:2=vncuser +Configure Xvnc options +To configure Xvnc parameters, you need to go to the same directory where you did the user mapping and open vncserver-config-defaults configuration file. This file is for the default Xvnc configuration and will be applied to every user unless any of the following applies: The user has its own configuration in $HOME/.vnc/config The same option with different value is configured in vncserver-config-mandatory configuration file, which replaces the default configuration and has even a higher priority than the per-user configuration. This option is for system administrators when they want to force particular Xvnc options. + +Format of the configuration file is also quite simple as the configuration is in form of + +option=value +option +for example + +session=gnome +securitytypes=vncauth,tlsvnc +desktop=sandbox +geometry=2000x1200 +localhost +alwaysshared +Note: +There is one important option you need to set and that option is the session you want to start. E.g when you want to start GNOME desktop, then you have to use + +session=gnome +which should match the name of a session desktop file from /usr/share/xsessions directory. + +Set VNC password +You need to set a password for each user in order to be able to start the Tigervnc server. In order to create a password, you just run + +$ vncpasswd +as the user you will be starting the server for. + +Note: +If you were using Tigervnc before for your user and you already created a password, then you will have to make sure the $HOME/.vnc folder created by vncpasswd will have the correct SELinux context. You either can delete this folder and recreate it again by creating the password one more time, or alternatively you can run + +$ restorecon -RFv /home//.vnc +Start the Tigervnc server +Finally you can start the server using systemd service. To do so just run + +$ systemctl start vncserver@:x +as root or + +$ sudo systemctl start vncserver@:x +as a regular user in case it has permissions to run sudo. Don't forget to replace the :x by the actual number you configured in the user mapping file. Following our example by running + +$ systemctl start vncserver@:1 +you will start a Tigervnc server for user test with a GNOME session. + +Note: +If you were previously using Tigervnc and you were used to start it using systemd then you will need to remove previous systemd configuration files, those you most likely copied to /etc/systemd/system/vncserver@.service, otherwise this service file will be preferred over the new one installed with latest Tigervnc. + +Limitations +You will not be able to start a Tigervnc server for a user who is already logged into a graphical session. Avoid running the server as the root user as it's not a safe thing to do. While running the server as the root should work in general, it's not recommended to do so and there might be some things which are not working properly. \ No newline at end of file diff --git a/fix-build-error-with-xorg-server-1.20.8.patch b/fix-build-error-with-xorg-server-1.20.8.patch deleted file mode 100644 index 25fa9d893dc364272fe4d33cca43342dad39e88e..0000000000000000000000000000000000000000 --- a/fix-build-error-with-xorg-server-1.20.8.patch +++ /dev/null @@ -1,26 +0,0 @@ -Description: Build fix for xorg-server 1.20.7, which moved ddxInputThread call from os layer into ddx layer. -Author: Lifted from OpenSUSE Tumbleweed tigervnc-1.10.0-5.1 source rpm. - -Index: pkg-tigervnc/unix/xserver/hw/vnc/xvnc.c -=================================================================== ---- pkg-tigervnc.orig/unix/xserver/hw/vnc/xvnc.c -+++ pkg-tigervnc/unix/xserver/hw/vnc/xvnc.c -@@ -295,6 +295,15 @@ void ddxBeforeReset(void) - } - #endif - -+#if INPUTTHREAD -+/** This function is called in Xserver/os/inputthread.c when starting -+ the input thread. */ -+void -+ddxInputThreadInit(void) -+{ -+} -+#endif -+ - void ddxUseMsg(void) - { - vncPrintBanner(); --- -1.8.3.1 - diff --git a/tigervnc.spec b/tigervnc.spec index 5d22df222caf6c025292033e012a277b43913435..15239dc133dc99b75493cec07f94e1924c5f3094 100644 --- a/tigervnc.spec +++ b/tigervnc.spec @@ -1,37 +1,38 @@ %global _hardened_build 1 +%global selinuxtype targeted +%global modulename vncsession Name: tigervnc -Version: 1.10.1 -Release: 6 +Version: 1.12.0 +Release: 1 Summary: A TigerVNC remote display system License: GPLv2+ URL: http://github.com/TigerVNC/tigervnc/ -Source0: https://github.com/TigerVNC/tigervnc/archive/v1.10.1.tar.gz +Source0: https://github.com/TigerVNC/tigervnc/archive/v1.12.0.tar.gz Source1: vncserver.service -Source2: vncserver.sysconfig +Source2: vncserver Source3: 10-libvnc.conf Source4: xvnc.service Source5: xvnc.socket +Source6: HOWTO.md Patch0001: tigervnc-xserver120.patch -Patch0002: fix-build-error-with-xorg-server-1.20.8.patch -Patch0003: CVE-2020-26117.patch BuildRequires: gcc-c++ systemd cmake automake autoconf gettext gettext-autopoint pixman-devel fltk-devel >= 1.3.3 BuildRequires: libX11-devel libtool libxkbfile-devel libpciaccess-devel libXinerama-devel libXfont2-devel BuildRequires: libXext-devel xorg-x11-server-source libXi-devel libXdmcp-devel libxshmfence-devel BuildRequires: xorg-x11-xtrans-devel xorg-x11-util-macros xorg-x11-server-devel libXtst-devel libdrm-devel libXt-devel -BuildRequires: openssl-devel mesa-libGL-devel freetype-devel desktop-file-utils java-devel jpackage-utils pam-devel gnutls-devel libjpeg-turbo-devel +BuildRequires: openssl-devel mesa-libGL-devel freetype-devel desktop-file-utils java-devel jpackage-utils pam-devel gnutls-devel libjpeg-turbo-devel selinux-policy-devel Requires(post): coreutils Requires(postun):coreutils Requires: hicolor-icon-theme -Provides: %{name}-license = %{version}-%{release} %{name}-icons = %{version}-%{release} -Obsoletes: %{name}-license < %{version}-%{release} %{name}-icons < %{version}-%{release} +Provides: %{name}-icons = %{name}-%{release} +Obsoletes: %{name}-icons < %{name}-%{release} %description This package provides client for Virtual Network Computing (VNC), with which @@ -40,6 +41,7 @@ you can access any other desktops running a VNC server. %package server Summary: A TigerVNC server Requires: perl-interpreter tigervnc-server-minimal xorg-x11-xauth xorg-x11-xinit +Requires: (tigervnc-selinux if selinux-policy-%{selinuxtype}) %description server This package provides full installaion of TigerCNC and utilities that @@ -49,7 +51,7 @@ X session. %package server-minimal Summary: A minimal installation of TigerVNC server -Requires: mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils %{name} +Requires: mesa-dri-drivers, xkeyboard-config, %{name}-license xkbcomp %description server-minimal This package provides minimal installation of TigerVNC, with which @@ -57,7 +59,7 @@ other people can access your desktop on your machine. %package server-module Summary: TigerVNC module to Xorg -Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) %{name} +Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv) %{name}-license %description server-module This package contains libvnc.so module to X server, allowing others @@ -71,6 +73,22 @@ BuildArch: noarch %description server-applet If you want to use web browser in clients, please install this package. +%package selinux +Summary: SElinux module for TigerVNC +BuildRequires: selinux-policy-devel +Requires: selinux-policy-targeted +BuildArch: noarch + +%description selinux +This package provides the SElinux policy module to ensure Tigervnc runs properly under an environment with SElinux enabled + +%package license +Summary: License of Tigervnc suite +BuildArch: noarch + +%description license +This package contains license of the Tigervnc suite + %package_help %prep @@ -78,8 +96,6 @@ If you want to use web browser in clients, please install this package. cp -r /usr/share/xorg-x11-server-source/* unix/xserver %patch0001 -p1 -b .xserver120-rebased -%patch0002 -p1 -%patch0003 -p1 pushd unix/xserver for all in `find . -type f -perm -001`; do @@ -111,6 +127,11 @@ pushd media make popd +# SElinux +pushd unix/vncserver/selinux +make +popd + # Build Java applet pushd java %{cmake} . @@ -122,19 +143,19 @@ popd rm -f %{buildroot}%{_docdir}/%{name}-%{version}/{README.rst,LICENCE.TXT} pushd unix/xserver/hw/vnc +%make_install +popd + +pushd unix/vncserver/selinux make install DESTDIR=%{buildroot} popd # Install systemd unit file mkdir -p %{buildroot}%{_unitdir} -install -m644 %{SOURCE1} %{buildroot}%{_unitdir}/vncserver@.service install -m644 %{SOURCE4} %{buildroot}%{_unitdir}/xvnc@.service install -m644 %{SOURCE5} %{buildroot}%{_unitdir}/xvnc.socket rm -rf %{buildroot}%{_initrddir} -mkdir -p %{buildroot}%{_sysconfdir}/sysconfig -install -m644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/vncservers - # Install desktop stuff mkdir -p %{buildroot}%{_datadir}/icons/hicolor/{16x16,24x24,48x48}/apps @@ -144,6 +165,7 @@ install -m644 tigervnc_$s.png %{buildroot}%{_datadir}/icons/hicolor/${s}x$s/apps done popd +install -m 644 %{SOURCE2} %{buildroot}%{_bindir}/vncserver # Install Java applet pushd java @@ -159,23 +181,30 @@ rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/ install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf +install -m 644 %{SOURCE6} %{buildroot}%{_docdir}/tigervnc/HOWTO.md + + %files -f %{name}.lang %defattr(-,root,root) %doc README.rst -%license LICENCE.TXT %{_bindir}/vncviewer %{_datadir}/applications/* -%license LICENCE.TXT %{_datadir}/icons/hicolor/*/apps/* %files server %defattr(-,root,root) -%config(noreplace) %{_sysconfdir}/sysconfig/vncservers -%{_bindir}/vncserver -%{_bindir}/x0vncserver +%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}/vncserver +%{_bindir}/x0vncserver +%{_sbindir}/vncsession +%{_libexecdir}/vncserver +%{_libexecdir}/vncsession-start %files server-minimal %defattr(-,root,root) @@ -192,17 +221,26 @@ install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.c %defattr(-,root,root) %{_datadir}/vnc/classes/* +%files license +%{_docdir}/tigervnc/LICENCE.TXT + +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.* +%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} + %files help %defattr(-,root,root) %doc java/com/tigervnc/vncviewer/README +%{_docdir}/tigervnc/HOWTO.md %{_mandir}/man1/* +%{_mandir}/man8/* %changelog -* Wed Nov 3 2021 Li Jingwei - 1.10.1-6 -- Type:bugfix +* Tue Mar 22 2022 xinghe - 1.12.0-1 +- Type:requirements - ID:NA - SUG:NA -- DESC:correct provides version typo in spec file +- DESC:update tigervnc to 1.12.0 * Thu Oct 29 2020 yanan - 1.10.1-5 - Type:cves diff --git a/v1.10.1.tar.gz b/v1.10.1.tar.gz deleted file mode 100644 index 64c281ff7e56082238a96e832096de5cc17e9dee..0000000000000000000000000000000000000000 Binary files a/v1.10.1.tar.gz and /dev/null differ diff --git a/v1.12.0.tar.gz b/v1.12.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..04a970eac6c751817dd611d8d77f26811e70f361 Binary files /dev/null and b/v1.12.0.tar.gz differ diff --git a/vncserver b/vncserver new file mode 100644 index 0000000000000000000000000000000000000000..5051f52da914cdf27690983efde2dab92f0c6160 --- /dev/null +++ b/vncserver @@ -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)) { + die "A VNC server is already running as :$displayNumber\n"; + } +} 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} = "edString($desktopName); +$default_opts{auth} = "edString($xauthorityFile); +$default_opts{geometry} = $geometry if ($geometry); +$default_opts{depth} = $depth if ($depth); +$default_opts{pixelformat} = $pixelformat if ($pixelformat); +$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, 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 .= " " . "edString($arg); +} +$cmd .= " >> " . "edString($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 () { 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 >> " . "edString($desktopLog) . " 2>&1"); + } + if (kill 0, `cat $pidFile`) { + $opt{'-kill'} = ':'.$displayNumber; + &Kill(); + } +} else { + if ($opt{'-autokill'}) { + if (! $skipxstartup) { + system("($xstartupFile; $0 -kill :$displayNumber) >> " + . "edString($desktopLog) . " 2>&1 &"); + } + } else { + if (! $skipxstartup) { + system("$xstartupFile >> " . "edString($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 () { + 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 [:] [-name ] [-depth ]\n". + " [-geometry x]\n". + " [-pixelformat rgbNNN|bgrNNN]\n". + " [-fp ]\n". + " [-cc ]\n". + " [-fg]\n". + " [-autokill]\n". + " [-noxstartup]\n". + " [-xstartup ]\n". + " ...\n\n". + " $prog -kill \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 : 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"; +} \ No newline at end of file diff --git a/vncserver.sysconfig b/vncserver.sysconfig deleted file mode 100644 index 4d0489b422477e421aed252a86d9d97e8be3ad89..0000000000000000000000000000000000000000 --- a/vncserver.sysconfig +++ /dev/null @@ -1 +0,0 @@ -# THIS FILE HAS BEEN REPLACED BY /lib/systemd/system/vncserver@.service