diff options
author | Samuel Mannehed (ThinLinc team) <samuel@cendio.se> | 2024-05-07 15:00:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-07 15:00:43 +0200 |
commit | 3db859ef6c40539ac20cd5e33e0f31e00dc1a4a3 (patch) | |
tree | 9d911240e3456f0a9ca664bc242169e56efea6b9 | |
parent | 6d19e961e243a6a5a517afd2dc3602ce013e4433 (diff) | |
parent | 337c136ce018fc8d9d12b9e188634925238d11cc (diff) | |
download | tigervnc-3db859ef6c40539ac20cd5e33e0f31e00dc1a4a3.tar.gz tigervnc-3db859ef6c40539ac20cd5e33e0f31e00dc1a4a3.zip |
Merge pull request #1737 from 62832/fix-1195
Allow for alternative user config locations, deprecate `~/.vnc` in favour of XDG Base Directory Specification paths
30 files changed, 380 insertions, 167 deletions
@@ -10,3 +10,6 @@ CMakeCache.txt Makefile Makefile.in config.h +cmake_install.cmake +cmake_uninstall.cmake +install_manifest.txt diff --git a/common/os/os.cxx b/common/os/os.cxx index 2dfabc46..35f87b03 100644 --- a/common/os/os.cxx +++ b/common/os/os.cxx @@ -24,6 +24,8 @@ #include <os/os.h> #include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> #ifndef WIN32 #include <pwd.h> @@ -31,20 +33,21 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> #include <unistd.h> #else #include <windows.h> #include <wininet.h> /* MinGW needs it */ #include <shlobj.h> +#define stat _stat #endif -static const char* gethomedir(bool userDir) +static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def) { - static char dir[PATH_MAX]; + static char dir[PATH_MAX], legacy[PATH_MAX]; + struct stat st; #ifndef WIN32 - char *homedir; + char *homedir, *xdgdir; uid_t uid; struct passwd *passwd; #else @@ -66,10 +69,17 @@ static const char* gethomedir(bool userDir) if (userDir) return homedir; - snprintf(dir, sizeof(dir), "%s/.vnc", homedir); + xdgdir = getenv(xdg_env); + if (xdgdir != NULL && xdgdir[0] == '/') + snprintf(dir, sizeof(dir), "%s/tigervnc", xdgdir); + else + snprintf(dir, sizeof(dir), "%s/%s/tigervnc", homedir, xdg_def); - return dir; + snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir); #else + (void) xdg_def; + (void) xdg_env; + if (userDir) ret = SHGetSpecialFolderPath(NULL, dir, CSIDL_PROFILE, FALSE); else @@ -81,22 +91,38 @@ static const char* gethomedir(bool userDir) if (userDir) return dir; - if (strlen(dir) + strlen("\\vnc") >= sizeof(dir)) + ret = SHGetSpecialFolderPath(NULL, legacy, CSIDL_APPDATA, FALSE); + + if (ret == FALSE) return NULL; - strcat(dir, "\\vnc"); + if (strlen(dir) + strlen("\\TigerVNC") >= sizeof(dir)) + return NULL; + if (strlen(legacy) + strlen("\\vnc") >= sizeof(legacy)) + return NULL; - return dir; + strcat(dir, "\\TigerVNC"); + strcat(legacy, "\\vnc"); #endif + return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir; } -const char* os::getvnchomedir() +const char* os::getuserhomedir() { - return gethomedir(false); + return getvncdir(true, NULL, NULL); } -const char* os::getuserhomedir() +const char* os::getvncconfigdir() { - return gethomedir(true); + return getvncdir(false, "XDG_CONFIG_HOME", ".config"); } +const char* os::getvncdatadir() +{ + return getvncdir(false, "XDG_DATA_HOME", ".local/share"); +} + +const char* os::getvncstatedir() +{ + return getvncdir(false, "XDG_STATE_HOME", ".local/state"); +} diff --git a/common/os/os.h b/common/os/os.h index 5f927fef..8e522676 100644 --- a/common/os/os.h +++ b/common/os/os.h @@ -23,22 +23,44 @@ namespace os { /* - * Get VNC home directory ($HOME/.vnc or %APPDATA%/vnc/). + * Get user home directory. * If HOME environment variable is set then it is used. * Otherwise home directory is obtained via getpwuid function. * * Returns NULL on failure. */ - const char* getvnchomedir(); + const char* getuserhomedir(); /* - * Get user home directory. - * If HOME environment variable is set then it is used. - * Otherwise home directory is obtained via getpwuid function. + * Get VNC config directory. On Unix-like systems, this is either: + * - $XDG_CONFIG_HOME/tigervnc + * - $HOME/.config/tigervnc + * On Windows, this is simply %APPDATA%/TigerVNC/. * * Returns NULL on failure. */ - const char* getuserhomedir(); + const char* getvncconfigdir(); + + /* + * Get VNC data directory used for X.509 known hosts. + * On Unix-like systems, this is either: + * - $XDG_DATA_HOME/tigervnc + * - $HOME/.local/share/tigervnc + * On Windows, this is simply %APPDATA%/TigerVNC/. + * + * Returns NULL on failure. + */ + const char* getvncdatadir(); + + /* + * Get VNC state (logs) directory. On Unix-like systems, this is either: + * - $XDG_STATE_HOME/tigervnc + * - $HOME/.local/state/tigervnc + * On Windows, this is simply %APPDATA%/TigerVNC/. + * + * Returns NULL on failure. + */ + const char* getvncstatedir(); } diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index 90540959..cc0ca89f 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -58,28 +58,27 @@ using namespace rfb; -static const char* homedirfn(const char* fn); +static const char* configdirfn(const char* fn); StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", - homedirfn("x509_ca.pem"), + configdirfn("x509_ca.pem"), ConfViewer); StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", - homedirfn("x509_crl.pem"), + configdirfn("x509_crl.pem"), ConfViewer); static LogWriter vlog("TLS"); -static const char* homedirfn(const char* fn) +static const char* configdirfn(const char* fn) { static char full_path[PATH_MAX]; - const char* homedir; + const char* configdir; - homedir = os::getvnchomedir(); - if (homedir == NULL) + configdir = os::getvncconfigdir(); + if (configdir == NULL) return ""; - snprintf(full_path, sizeof(full_path), "%s/%s", homedir, fn); - + snprintf(full_path, sizeof(full_path), "%s/%s", configdir, fn); return full_path; } @@ -308,7 +307,7 @@ void CSecurityTLS::checkSession() int err; bool hostname_match; - const char *homeDir; + const char *hostsDir; gnutls_datum_t info; size_t len; @@ -385,14 +384,14 @@ void CSecurityTLS::checkSession() /* Certificate has some user overridable problems, so TOFU time */ - homeDir = os::getvnchomedir(); - if (homeDir == NULL) { - throw AuthFailureException("Could not obtain VNC home directory " + hostsDir = os::getvncdatadir(); + if (hostsDir == NULL) { + throw AuthFailureException("Could not obtain VNC data directory " "path for known hosts storage"); } std::string dbPath; - dbPath = (std::string)homeDir + "/x509_known_hosts"; + dbPath = (std::string)hostsDir + "/x509_known_hosts"; err = gnutls_verify_stored_pubkey(dbPath.c_str(), NULL, client->getServerName(), NULL, diff --git a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf index a053a7d8..9a69fc7d 100644 --- a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf +++ b/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf @@ -15,5 +15,5 @@ # Identifier "Screen0 # DefaultDepth 16 # Option "SecurityTypes" "VncAuth" -# Option "PasswordFile" "/root/.vnc/passwd" +# Option "PasswordFile" "/root/.config/tigervnc/passwd" #EndSection diff --git a/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf index a053a7d8..9a69fc7d 100644 --- a/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf +++ b/contrib/packages/rpm/el8/SOURCES/10-libvnc.conf @@ -15,5 +15,5 @@ # Identifier "Screen0 # DefaultDepth 16 # Option "SecurityTypes" "VncAuth" -# Option "PasswordFile" "/root/.vnc/passwd" +# Option "PasswordFile" "/root/.config/tigervnc/passwd" #EndSection diff --git a/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf index a053a7d8..9a69fc7d 100644 --- a/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf +++ b/contrib/packages/rpm/el9/SOURCES/10-libvnc.conf @@ -15,5 +15,5 @@ # Identifier "Screen0 # DefaultDepth 16 # Option "SecurityTypes" "VncAuth" -# Option "PasswordFile" "/root/.vnc/passwd" +# Option "PasswordFile" "/root/.config/tigervnc/passwd" #EndSection diff --git a/java/.gitignore b/java/.gitignore new file mode 100644 index 00000000..a99543fd --- /dev/null +++ b/java/.gitignore @@ -0,0 +1,4 @@ +*.class +*.jar +.idea/ +timestamp diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java index 14a5eb66..ab221427 100644 --- a/java/com/tigervnc/rfb/CSecurityTLS.java +++ b/java/com/tigervnc/rfb/CSecurityTLS.java @@ -89,13 +89,13 @@ public class CSecurityTLS extends CSecurity { public static String getDefaultCA() { if (UserPreferences.get("viewer", "x509ca") != null) return UserPreferences.get("viewer", "x509ca"); - return FileUtils.getVncHomeDir()+"x509_ca.pem"; + return FileUtils.getVncConfigDir()+"x509_ca.pem"; } public static String getDefaultCRL() { if (UserPreferences.get("viewer", "x509crl") != null) return UserPreferences.get("viewer", "x509crl"); - return FileUtils.getVncHomeDir()+"x509_crl.pem"; + return FileUtils.getVncConfigDir()+"x509_crl.pem"; } public static void setDefaults() @@ -277,12 +277,12 @@ public class CSecurityTLS extends CSecurity { "do you want to continue?")) throw new AuthFailureException("server certificate has expired"); } - File vncDir = new File(FileUtils.getVncHomeDir()); + File vncDir = new File(FileUtils.getVncDataDir()); if (!vncDir.exists()) { try { vncDir.mkdir(); } catch(SecurityException e) { - throw new AuthFailureException("Could not obtain VNC home directory "+ + throw new AuthFailureException("Could not obtain VNC data directory "+ "path for known hosts storage"); } } @@ -356,7 +356,6 @@ public class CSecurityTLS extends CSecurity { private void store_pubkey(File dbPath, String serverName, String pk) { ArrayList<String> lines = new ArrayList<String>(); - File vncDir = new File(FileUtils.getVncHomeDir()); try { if (dbPath.exists()) { FileReader db = new FileReader(dbPath); diff --git a/java/com/tigervnc/vncviewer/FileUtils.java b/java/com/tigervnc/vncviewer/FileUtils.java index af5da3c2..95fec3e6 100644 --- a/java/com/tigervnc/vncviewer/FileUtils.java +++ b/java/com/tigervnc/vncviewer/FileUtils.java @@ -22,9 +22,11 @@ import javax.swing.filechooser.FileSystemView; import com.tigervnc.rfb.LogWriter; +import java.io.File; + public class FileUtils { - public static final String getHomeDir() { + public static String getHomeDir() { String homeDir = null; try { String os = System.getProperty("os.name"); @@ -56,21 +58,47 @@ public class FileUtils { vlog.error("Cannot access os.name system property:"+e.getMessage()); } - String separator = null; - try { - separator = Character.toString(java.io.File.separatorChar); - } catch(java.security.AccessControlException e) { - vlog.error("Cannot access file.separator system property:"+e.getMessage()); + return homeDir + getFileSeparator(); + } + + public static String getVncDir(String xdgEnv, String xdgDefault) { + File legacyDir = new File(getHomeDir() + ".vnc" + getFileSeparator()); + String os = System.getProperty("os.name"); + + if (os.startsWith("Windows")) { + File newDir = new File(System.getenv("APPDATA") + getFileSeparator() + "TigerVNC" + getFileSeparator()); + if (!newDir.exists()) { + newDir.mkdirs(); + } + File[] existingFiles = legacyDir.listFiles(); + if (existingFiles != null) { + for (File file : existingFiles) { + file.renameTo(new File(newDir.getPath() + file.getName())); + } + legacyDir.delete(); + } + return newDir.getPath(); + } else { + if (legacyDir.exists()) { + vlog.info("WARNING: ~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."); + return legacyDir.getPath(); + } + String xdgBaseDir = System.getenv(xdgEnv); + return (xdgBaseDir != null && xdgBaseDir.startsWith("/")) + ? xdgBaseDir + getFileSeparator() + "tigervnc" + getFileSeparator() + : getHomeDir() + xdgDefault + getFileSeparator() + "tigervnc" + getFileSeparator(); } + } - return homeDir + getFileSeparator(); + public static String getVncConfigDir() { + return getVncDir("XDG_CONFIG_HOME", ".config"); } - public static final String getVncHomeDir() { - return getHomeDir()+".vnc"+getFileSeparator(); + public static String getVncDataDir() { + return getVncDir("XDG_DATA_HOME", ".local" + getFileSeparator() + "share"); } - public static final String getFileSeparator() { + public static String getFileSeparator() { String separator = null; try { separator = Character.toString(java.io.File.separatorChar); diff --git a/java/com/tigervnc/vncviewer/Parameters.java b/java/com/tigervnc/vncviewer/Parameters.java index f08202c0..8c8465cb 100644 --- a/java/com/tigervnc/vncviewer/Parameters.java +++ b/java/com/tigervnc/vncviewer/Parameters.java @@ -325,13 +325,6 @@ public class Parameters { if (filename == null || filename.isEmpty()) { saveToReg(servername); return; - /* - String homeDir = FileUtils.getVncHomeDir(); - if (homeDir == null) - throw new Exception("Failed to read configuration file, "+ - "can't obtain home directory path."); - filepath = homeDir.concat("default.tigervnc"); - */ } else { filepath = filename; } @@ -385,16 +378,7 @@ public class Parameters { String filepath; if (filename == null) { - - return loadFromReg(); - - /* - String homeDir = FileUtils.getVncHomeDir(); - if (homeDir == null) - throw new Exception("Failed to read configuration file, "+ - "can't obtain home directory path."); - filepath = homeDir.concat("default.tigervnc"); - */ + return loadFromReg(); } else { filepath = filename; } diff --git a/java/com/tigervnc/vncviewer/ServerDialog.java b/java/com/tigervnc/vncviewer/ServerDialog.java index aeee0b21..5f75fd3d 100644 --- a/java/com/tigervnc/vncviewer/ServerDialog.java +++ b/java/com/tigervnc/vncviewer/ServerDialog.java @@ -235,7 +235,7 @@ class ServerDialog extends Dialog implements Runnable { private void handleLoad() { String title = "Select a TigerVNC configuration file"; - File dflt = new File(FileUtils.getVncHomeDir().concat("default.tigervnc")); + File dflt = new File(FileUtils.getVncConfigDir().concat("default.tigervnc")); FileNameExtensionFilter filter = new FileNameExtensionFilter("TigerVNC configuration (*.tigervnc)", "tigervnc"); File f = showChooser(title, dflt, filter); @@ -245,9 +245,9 @@ class ServerDialog extends Dialog implements Runnable { private void handleSaveAs() { String title = "Save the TigerVNC configuration to file"; - File dflt = new File(FileUtils.getVncHomeDir().concat("default.tigervnc")); + File dflt = new File(FileUtils.getVncConfigDir().concat("default.tigervnc")); if (!dflt.exists() || !dflt.isFile()) - dflt = new File(FileUtils.getVncHomeDir()); + dflt = new File(FileUtils.getVncConfigDir()); FileNameExtensionFilter filter = new FileNameExtensionFilter("TigerVNC configuration (*.tigervnc)", "tigervnc"); File f = showChooser(title, dflt, filter); diff --git a/tests/.gitignore b/tests/.gitignore index 110f2510..bc2748d9 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,6 +1,11 @@ conv +convertlf convperf decperf +emulatemb encperf fbperf +gesturehandler hostport +pixelformat +unicode diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx index 93ad6f6f..68c44289 100644 --- a/unix/vncpasswd/vncpasswd.cxx +++ b/unix/vncpasswd/vncpasswd.cxx @@ -156,13 +156,22 @@ int main(int argc, char** argv) } if (fname[0] == '\0') { - const char *homeDir = os::getvnchomedir(); - if (homeDir == NULL) { - fprintf(stderr, "Can't obtain VNC home directory\n"); + const char *configDir = os::getvncconfigdir(); + if (configDir == NULL) { + fprintf(stderr, "Can't obtain VNC config directory\n"); exit(1); } - mkdir(homeDir, 0777); - snprintf(fname, sizeof(fname), "%s/passwd", homeDir); + strcpy(fname, configDir); + char *p = NULL; + for (p = fname + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + mkdir(fname, 0777); + *p = '/'; + } + } + mkdir(fname, 0777); + snprintf(fname, sizeof(fname), "%s/passwd", configDir); } while (true) { diff --git a/unix/vncpasswd/vncpasswd.man b/unix/vncpasswd/vncpasswd.man index c70a425a..71c6461a 100644 --- a/unix/vncpasswd/vncpasswd.man +++ b/unix/vncpasswd/vncpasswd.man @@ -9,11 +9,12 @@ vncpasswd \- change the VNC password .B vncpasswd allows you to set the password used to access VNC desktops. Its default behavior is to prompt for a VNC password and then store an obfuscated version -of this password to \fIpasswd-file\fR (or to $HOME/.vnc/passwd if no password -file is specified.) The \fBvncserver\fP script runs \fBvncpasswd\fP the first -time you start a VNC desktop, and it invokes \fBXvnc\fP with the appropriate -\fB\-rfbauth\fP option. \fBvncviewer\fP can also be given a password file to -use via the \fB\-passwd\fP option. +of this password to \fIpasswd-file\fR (or to +\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP if no passwordfile is specified.) The +\fBvncserver\fP script runs \fBvncpasswd\fP the first time you start a VNC +desktop, and it invokes \fBXvnc\fP with the appropriate \fB\-rfbauth\fP option. +\fBvncviewer\fP can also be given a password file to use via the \fB\-passwd\fP +option. The password must be at least six characters long (unless the \fB\-f\fR command-line option is used-- see below), and only the first eight @@ -38,7 +39,9 @@ character. .SH FILES .TP -$HOME/.vnc/passwd +\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP +.TQ +\fI$HOME/.config/tigervnc/passwd\fP Default location of the VNC password file. .SH SEE ALSO diff --git a/unix/vncserver/.gitignore b/unix/vncserver/.gitignore new file mode 100644 index 00000000..879eae0c --- /dev/null +++ b/unix/vncserver/.gitignore @@ -0,0 +1,5 @@ +vncserver +vncserver@.service +vncsession +vncsession-start +vncsession.man diff --git a/unix/vncserver/HOWTO.md b/unix/vncserver/HOWTO.md index 9f53048e..f422eb2a 100644 --- a/unix/vncserver/HOWTO.md +++ b/unix/vncserver/HOWTO.md @@ -30,7 +30,8 @@ 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 user has its own configuration in `$XDG_CONFIG_HOME/tigervnc/config` + or `$HOME/.config/tigervnc/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 @@ -74,10 +75,10 @@ You need to run it as the user who will run the server. ### Note: If you used TigerVNC before with your user and you already created a -password, then you have to make sure the `$HOME/.vnc` folder created by -`vncpasswd` 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: +password, then you have to make sure the (legacy, if used) `$HOME/.vnc` +folder created by `vncpasswd` has 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/<USER>/.vnc ``` diff --git a/unix/vncserver/selinux/vncsession.fc b/unix/vncserver/selinux/vncsession.fc index bc81f8f2..9ad7d0fb 100644 --- a/unix/vncserver/selinux/vncsession.fc +++ b/unix/vncserver/selinux/vncsession.fc @@ -19,6 +19,12 @@ HOME_DIR/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) /root/\.vnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +HOME_DIR/\.config/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +/root/\.config/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +HOME_DIR/\.local/share/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +/root/\.local/share/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +HOME_DIR/\.local/state/tigervnc(/.*)? gen_context(system_u:object_r:vnc_home_t,s0) +/root/\.local/state/tigervnc(/.*)? 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) diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te index 680be8ea..d92f1bda 100644 --- a/unix/vncserver/selinux/vncsession.te +++ b/unix/vncserver/selinux/vncsession.te @@ -37,6 +37,18 @@ 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) +# Allowed to create ~/.local +optional_policy(` + gnome_filetrans_home_content(vnc_session_t) +') +optional_policy(` + gen_require(` + type gconf_home_t; + ') + create_dirs_pattern(vnc_session_t, gconf_home_t, gconf_home_t) +') + +# Manage TigerVNC files (mainly ~/.local/state/*.log) 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) @@ -72,13 +84,16 @@ optional_policy(` userdom_spec_domtrans_all_users(vnc_session_t) userdom_signal_all_users(vnc_session_t) - userdom_user_home_dir_filetrans(vnc_session_t, vnc_home_t, dir, ".vnc") - userdom_admin_home_dir_filetrans(vnc_session_t, vnc_home_t, dir, ".vnc") - - # This also affects other tools, e.g. vncpasswd + # Make sure legacy path has correct type gen_require(` attribute userdomain; + type gconf_home_t; ') userdom_admin_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc") userdom_user_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc") + + gnome_config_filetrans(userdomain, vnc_home_t, dir, "tigervnc") + gnome_data_filetrans(userdomain, vnc_home_t, dir, "tigervnc") + filetrans_pattern(userdomain, gconf_home_t, vnc_home_t, dir, "tigervnc") + filetrans_pattern(vnc_session_t, gconf_home_t, vnc_home_t, dir, "tigervnc") ') diff --git a/unix/vncserver/vncserver-config-defaults b/unix/vncserver/vncserver-config-defaults index 81d73886..2dc4314e 100644 --- a/unix/vncserver/vncserver-config-defaults +++ b/unix/vncserver/vncserver-config-defaults @@ -1,7 +1,7 @@ ## Default settings for VNC servers started by the vncserver service # # Any settings given here will override the builtin defaults, but can -# also be overriden by ~/.vnc/config and vncserver-config-mandatory. +# also be overriden by ~/.config/tigervnc/config and vncserver-config-mandatory. # # See HOWTO.md and the following manpages for more details: # vncsession(8) Xvnc(1) diff --git a/unix/vncserver/vncserver-config-mandatory b/unix/vncserver/vncserver-config-mandatory index cfff1bd9..dc716f11 100644 --- a/unix/vncserver/vncserver-config-mandatory +++ b/unix/vncserver/vncserver-config-mandatory @@ -1,7 +1,7 @@ ## Mandatory settings for VNC servers started by the vncserver service # # Any settings given here will override the builtin defaults and -# settings specified in ~/.vnc/config or vnc-config-defaults. +# settings specified in ~/.config/tigervnc/config or vnc-config-defaults. # # See HOWTO.md and the following manpages for more details: # vncsession(8) Xvnc(1) diff --git a/unix/vncserver/vncserver.in b/unix/vncserver/vncserver.in index 95d672b1..ebdd3a97 100755 --- a/unix/vncserver/vncserver.in +++ b/unix/vncserver/vncserver.in @@ -35,7 +35,15 @@ # your site # -$vncUserDir = "$ENV{HOME}/.vnc"; +$vncUserDir = rindex("$ENV{XDG_CONFIG_HOME}", "/", 0) == 0 + ? "$ENV{XDG_CONFIG_HOME}/tigervnc" + : "$ENV{HOME}/.config/tigervnc"; +$vncLegacyDir = "$ENV{HOME}/.vnc"; +if (!stat($vncUserDir) && stat($vncLegacyDir)) { + warn "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to."; + $vncUserDir = $vncLegacyDir; +} + $vncUserConfig = "$vncUserDir/config"; $vncSystemConfigDir = "@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc"; diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c index ba131fbd..3d21ae30 100644 --- a/unix/vncserver/vncsession.c +++ b/unix/vncserver/vncsession.c @@ -346,12 +346,54 @@ switch_user(const char *username, uid_t uid, gid_t gid) } static void +mkvncdir(const char *dir) +{ + if (mkdir(dir, 0755) == -1) { + if (errno != EEXIST) { + syslog(LOG_CRIT, "Failure creating \"%s\": %s", dir, strerror(errno)); + _exit(EX_OSERR); + } + +#ifdef HAVE_SELINUX + /* this is only needed to handle historical type changes for the legacy dir */ + int result; + if (selinux_file_context_verify(dir, 0) == 0) { + result = selinux_restorecon(dir, SELINUX_RESTORECON_RECURSE); + + if (result < 0) { + syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", dir, strerror(errno)); + } + } +#endif + } +} + +static void +mkdirrecursive(const char *dir) +{ + char *path = strdup(dir); + char *p; + + for (p = path + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + mkvncdir(path); + *p = '/'; + } + } + + mkvncdir(path); + free(path); +} + +static void redir_stdio(const char *homedir, const char *display) { int fd; long hostlen; - char* hostname = NULL; - char logfile[PATH_MAX]; + char* hostname = NULL, *xdgstate; + char logfile[PATH_MAX], legacy[PATH_MAX]; + struct stat st; fd = open("/dev/null", O_RDONLY); if (fd == -1) { @@ -364,25 +406,20 @@ redir_stdio(const char *homedir, const char *display) } close(fd); - snprintf(logfile, sizeof(logfile), "%s/.vnc", homedir); - if (mkdir(logfile, 0755) == -1) { - if (errno != EEXIST) { - syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno)); - _exit(EX_OSERR); - } + xdgstate = getenv("XDG_STATE_HOME"); + if (xdgstate != NULL && xdgstate[0] == '/') + snprintf(logfile, sizeof(logfile), "%s/tigervnc", xdgstate); + else + snprintf(logfile, sizeof(logfile), "%s/.local/state/tigervnc", homedir); -#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 + snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir); + if (stat(logfile, &st) != 0 && stat(legacy, &st) == 0) { + syslog(LOG_WARNING, "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to."); + strcpy(logfile, legacy); } + mkdirrecursive(logfile); + hostlen = sysconf(_SC_HOST_NAME_MAX); if (hostlen < 0) { syslog(LOG_CRIT, "sysconf(_SC_HOST_NAME_MAX): %s", strerror(errno)); @@ -395,8 +432,8 @@ redir_stdio(const char *homedir, const char *display) _exit(EX_OSERR); } - snprintf(logfile, sizeof(logfile), "%s/.vnc/%s%s.log", - homedir, hostname, display); + snprintf(logfile + strlen(logfile), sizeof(logfile) - strlen(logfile), "/%s%s.log", + hostname, display); free(hostname); fd = open(logfile, O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd == -1) { diff --git a/unix/vncserver/vncsession.man.in b/unix/vncserver/vncsession.man.in index d52da10b..a506ae21 100644 --- a/unix/vncserver/vncsession.man.in +++ b/unix/vncserver/vncsession.man.in @@ -27,27 +27,33 @@ debugging in a login shell from a terminal or for running from a terminal as an ordinary user. .SH FILES -Several VNC-related files are found in the directory $HOME/.vnc: +Several VNC-related files are found in the directory \fI$HOME/.config/tigervnc\fP: .TP -@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults -The optional system-wide equivalent of $HOME/.vnc/config. If this file exists -and defines options to be passed to Xvnc, they will be used as defaults for -users. The user's $HOME/.vnc/config overrides settings configured in this file. -The overall configuration file load order is: this file, $HOME/.vnc/config, -and then @CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory. None are required to exist. +\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults\fP +The optional system-wide equivalent of \fI$HOME/.config/tigervnc/config\fP. +If this file exists and defines options to be passed to Xvnc, they will be used +as defaults for users. The user's \fI$HOME/.config/tigervnc/config\fP overrides +settings configured in this file. The overall configuration file load order is: +this file, \fI$HOME/.config/tigervnc/config\fP, and then +\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP. +None are required to exist. .TP -@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory -The optional system-wide equivalent of $HOME/.vnc/config. If this file exists -and defines options to be passed to Xvnc, they will override any of the same -options defined in a user's $HOME/.vnc/config. This file offers a mechanism -to establish some basic form of system-wide policy. WARNING! There is -nothing stopping users from constructing their own vncsession-like script -that calls Xvnc directly to bypass any options defined in -@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory. The overall configuration file load -order is: @CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then -this file. None are required to exist. +\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP +The optional system-wide equivalent of \fI$HOME/.config/tigervnc/config\fP. +If this file exists and defines options to be passed to Xvnc, they will override +any of the same options defined in a user's \fI$HOME/.config/tigervnc/config\fP. +This file offers a mechanism to establish some basic form of system-wide policy. +WARNING! There is nothing stopping users from constructing their own +vncsession-like script that calls Xvnc directly to bypass any options defined in +\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-mandatory\fP. The +overall configuration file load order is: +\fI@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc/vncserver-config-defaults\fP, +\fI$HOME/.config/tigervnc/config\fP, and then this file. None are required to +exist. .TP -$HOME/.vnc/config +\fI$XDG_CONFIG_HOME/tigervnc/config\fP +.TQ +\fI$HOME/.config/tigervnc/config\fP An optional server config file wherein options to be passed to Xvnc are listed to avoid hard-coding them to the physical invocation. List options in this file one per line. For those requiring an argument, simply separate the option from @@ -61,10 +67,14 @@ can be used to control which session type will be started. This should match one of the files in \fI/usr/share/xsessions\fP. E.g. if there is a file called "gnome.desktop", then "session=gnome" would be set to use that session type. .TP -$HOME/.vnc/passwd +\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP +.TQ +\fI$HOME/.config/tigervnc/passwd\fP The VNC password file. .TP -$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log +\fI$XDG_STATE_HOME/tigervnc/\fIBhost\fI:\fIBdisplay#\fI.log\fP +.TQ +\fI$HOME/.local/state/tigervnc/\fIBhost\fI:\fIBdisplay#\fI.log\fP The log file for Xvnc and the session. .SH SEE ALSO diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man index 075141fa..e43ba150 100644 --- a/unix/xserver/hw/vnc/Xvnc.man +++ b/unix/xserver/hw/vnc/Xvnc.man @@ -367,7 +367,7 @@ and -once, the Xvnc and associated X clients will die when the user logs out of the X session in the normal way. It is important to use a VNC password in this case. A typical entry in inetd.conf might be: -5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.vnc/passwd +5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.config/tigervnc/passwd In fact typically, you would have one entry for each user who uses VNC regularly, each of whom has their own dedicated TCP port which they use. In diff --git a/vncviewer/.gitignore b/vncviewer/.gitignore index feba068d..db3cc77d 100644 --- a/vncviewer/.gitignore +++ b/vncviewer/.gitignore @@ -1,3 +1,4 @@ vncviewer vncviewer.desktop.in vncviewer.desktop +org.tigervnc.vncviewer.metainfo.xml diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx index 6a766295..4d57b5fb 100644 --- a/vncviewer/ServerDialog.cxx +++ b/vncviewer/ServerDialog.cxx @@ -315,12 +315,12 @@ void ServerDialog::loadServerHistory() return; #endif - const char* homeDir = os::getvnchomedir(); - if (homeDir == NULL) - throw Exception(_("Could not obtain the home directory path")); + const char* stateDir = os::getvncstatedir(); + if (stateDir == NULL) + throw Exception(_("Could not obtain the state directory path")); char filepath[PATH_MAX]; - snprintf(filepath, sizeof(filepath), "%s/%s", homeDir, SERVER_HISTORY); + snprintf(filepath, sizeof(filepath), "%s/%s", stateDir, SERVER_HISTORY); /* Read server history from file */ FILE* f = fopen(filepath, "r"); @@ -381,12 +381,12 @@ void ServerDialog::saveServerHistory() return; #endif - const char* homeDir = os::getvnchomedir(); - if (homeDir == NULL) - throw Exception(_("Could not obtain the home directory path")); + const char* stateDir = os::getvncstatedir(); + if (stateDir == NULL) + throw Exception(_("Could not obtain the state directory path")); char filepath[PATH_MAX]; - snprintf(filepath, sizeof(filepath), "%s/%s", homeDir, SERVER_HISTORY); + snprintf(filepath, sizeof(filepath), "%s/%s", stateDir, SERVER_HISTORY); /* Write server history to file */ FILE* f = fopen(filepath, "w+"); diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx index 75d46dca..15ea4ee8 100644 --- a/vncviewer/parameters.cxx +++ b/vncviewer/parameters.cxx @@ -629,11 +629,11 @@ void saveViewerParameters(const char *filename, const char *servername) { return; #endif - const char* homeDir = os::getvnchomedir(); - if (homeDir == NULL) - throw Exception(_("Could not obtain the home directory path")); + const char* configDir = os::getvncconfigdir(); + if (configDir == NULL) + throw Exception(_("Could not obtain the config directory path")); - snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", homeDir); + snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", configDir); } else { snprintf(filepath, sizeof(filepath), "%s", filename); } @@ -733,11 +733,11 @@ char* loadViewerParameters(const char *filename) { return loadFromReg(); #endif - const char* homeDir = os::getvnchomedir(); - if (homeDir == NULL) - throw Exception(_("Could not obtain the home directory path")); + const char* configDir = os::getvncconfigdir(); + if (configDir == NULL) + throw Exception(_("Could not obtain the config directory path")); - snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", homeDir); + snprintf(filepath, sizeof(filepath), "%s/default.tigervnc", configDir); } else { snprintf(filepath, sizeof(filepath), "%s", filename); } diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx index 6eebf3d0..59be4812 100644 --- a/vncviewer/vncviewer.cxx +++ b/vncviewer/vncviewer.cxx @@ -429,17 +429,34 @@ static void init_fltk() #endif } -static void mkvnchomedir() +static int mkvncdir(const char *dir) { - // Create .vnc in the user's home directory if it doesn't already exist - const char* homeDir = os::getvnchomedir(); - if (homeDir == NULL) { - vlog.error(_("Could not obtain the home directory path")); - } else { - int result = mkdir(homeDir, 0755); - if (result == -1 && errno != EEXIST) - vlog.error(_("Could not create VNC home directory: %s"), strerror(errno)); + int result = mkdir(dir, 0755); + if (result == -1 && errno != EEXIST) { + vlog.error(_("Could not create VNC directory %s: %s"), dir, strerror(errno)); + return result; } + return 0; +} + +static void mkdirrecursive(const char *dir) +{ + char *path = strdup(dir); + char *p; + + for (p = path + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkvncdir(path) != 0) { + free(path); + return; + } + *p = '/'; + } + } + + mkvncdir(path); + free(path); } static void usage(const char *programName) @@ -728,7 +745,19 @@ int main(int argc, char** argv) migrateDeprecatedOptions(); - mkvnchomedir(); + char *confdir = strdup(os::getvncconfigdir()); +#ifndef WIN32 + char *dotdir = strrchr(confdir, '.'); + if (dotdir != NULL && strcmp(dotdir, ".vnc") == 0) + vlog.info(_("~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to.")); +#else + char *vncdir = strrchr(confdir, '\\'); + if (vncdir != NULL && strcmp(vncdir, "vnc") == 0) + vlog.info(_("%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location.")); +#endif + mkdirrecursive(os::getvncconfigdir()); + mkdirrecursive(os::getvncdatadir()); + mkdirrecursive(os::getvncstatedir()); CSecurity::upg = &dlg; #if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE) diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man index 928896a1..1a282126 100644 --- a/vncviewer/vncviewer.man +++ b/vncviewer/vncviewer.man @@ -147,19 +147,22 @@ every supported scheme. .B \-passwd, \-PasswordFile \fIpassword-file\fP If you are on a filesystem which gives you access to the password file used by the server, you can specify it here to avoid typing it in. It will usually be -"~/.vnc/passwd". +\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP, or \fI~/.config/tigervnc/passwd\fP +if the former is unset. . .TP .B \-X509CA \fIpath\fP Path to CA certificate to use when authenticating remote servers using any of the X509 security schemes (X509None, X509Vnc, etc.). Must be in PEM -format. Default is \fB$HOME/.vnc/x509_ca.pem\fP. +format. Default is \fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP, or +\fI~/.config/tigervnc/x509_ca.pem\fP. . .TP .B \-X509CRL \fIpath\fP Path to certificate revocation list to use in conjunction with \fB-X509CA\fP. Must also be in PEM format. Default is -\fB$HOME/.vnc/x509_crl.pem\fP. +\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP, or +\fI~/.config/tigervnc/x509_crl.pem\fP. . .TP .B \-Shared @@ -338,17 +341,33 @@ re-connect will be offered. Default is on. .SH FILES .TP -$HOME/.vnc/default.tigervnc +\fI$XDG_CONFIG_HOME/tigervnc/default.tigervnc\fP +.TQ +\fI$HOME/.config/tigervnc/default.tigervnc\fP Default configuration options. This file must have a "magic" first line of "TigerVNC Configuration file Version 1.0" (without quotes), followed by simple <setting>=<value> pairs of your choosing. The available settings are those shown in this man page. .TP -$HOME/.vnc/x509_ca.pem +\fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP +.TQ +\fI$HOME/.config/tigervnc/x509_ca.pem\fP Default CA certificate for authenticating servers. .TP -$HOME/.vnc/x509_crl.pem +\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP +.TQ +\fI$HOME/.config/tigervnc/x509_crl.pem\fP Default certificate revocation list. +.TP +\fI$XDG_DATA_HOME/tigervnc/x509_known_hosts\fP +.TQ +\fI$HOME/.local/share/tigervnc/x509_known_hosts\fP +Known hosts database for certificate-based authentication. +.TP +\fI$XDG_STATE_HOME/tigervnc/tigervnc.history\fP +.TQ +\fI$HOME/.local/state/tigervnc/tigervnc.history\fP +History file for hostnames that have been recently connected to. .SH SEE ALSO .BR Xvnc (1), |