diff --git a/.gitignore b/.gitignore index 2e86442253..c8a0172d48 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ *.mo *.la *.lo +*.class +*.jar .deps .libs @@ -10,3 +12,18 @@ CMakeCache.txt Makefile Makefile.in config.h + +*.xml +*.man +*.service +cmake_install.cmake +cmake_uninstall.cmake +install_manifest.txt +tests/unit/[a-z]* +!tests/unit/[a-z]*\. + +timestamp +vncserver +!unix/vncserver +vncsession +vncsession-start diff --git a/common/os/os.cxx b/common/os/os.cxx index 2dfabc46e0..5c49ce123b 100644 --- a/common/os/os.cxx +++ b/common/os/os.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #include #else #include @@ -39,12 +40,12 @@ #include #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]; #ifndef WIN32 - char *homedir; + char *homedir, *xdgdir; uid_t uid; struct passwd *passwd; #else @@ -66,7 +67,20 @@ static const char* gethomedir(bool userDir) if (userDir) return homedir; + // check if (deprecated) legacy path exists and use that if so snprintf(dir, sizeof(dir), "%s/.vnc", homedir); + struct stat st; + + if (stat(dir, &st) == 0) + return dir; + + if (xdg_def != NULL) { + xdgdir = getenv(xdg_env); + if (xdgdir != NULL) + snprintf(dir, sizeof(dir), "%s/tigervnc", xdgdir); + else + snprintf(dir, sizeof(dir), "%s/%s/tigervnc", homedir, xdg_def); + } return dir; #else @@ -90,13 +104,23 @@ static const char* gethomedir(bool userDir) #endif } -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::getvncstatedir() +{ + return getvncdir(false, "XDG_STATE_HOME", ".local/state"); +} + +/* deprecated */ +const char* os::getvnchomedir() +{ + return getvncdir(false, NULL, NULL); +} diff --git a/common/os/os.h b/common/os/os.h index 5f927fef1d..0561d36c1f 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. + * Get VNC config directory. On Unix-like systems, this is either: + * - $XDG_CONFIG_HOME/tigervnc + * - $HOME/.config/tigervnc + * On Windows, this is simply %APPDATA%/vnc/. + * + * Returns NULL on failure. + */ + const char* getvncconfigdir(); + + /* + * 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%/vnc/. + * + * Returns NULL on failure. + */ + const char* getvncstatedir(); + + /* + * Get legacy VNC home directory ($HOME/.vnc on Unix-likes). * If HOME environment variable is set then it is used. * Otherwise home directory is obtained via getpwuid function. * * Returns NULL on failure. + * + * Deprecated. */ - const char* getuserhomedir(); + const char* getvnchomedir(); } diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index 905409597b..e2edde8962 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -58,27 +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 +308,7 @@ void CSecurityTLS::checkSession() int err; bool hostname_match; - const char *homeDir; + const char *configDir; gnutls_datum_t info; size_t len; @@ -385,14 +385,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 " + configDir = os::getvncconfigdir(); + if (configDir == NULL) { + throw AuthFailureException("Could not obtain VNC config directory " "path for known hosts storage"); } std::string dbPath; - dbPath = (std::string)homeDir + "/x509_known_hosts"; + dbPath = (std::string)configDir + "/x509_known_hosts"; err = gnutls_verify_stored_pubkey(dbPath.c_str(), NULL, client->getServerName(), NULL, diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx index 93ad6f6f26..8c26588be7 100644 --- a/unix/vncpasswd/vncpasswd.cxx +++ b/unix/vncpasswd/vncpasswd.cxx @@ -156,13 +156,13 @@ 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); + mkdir(configDir, 0777); + snprintf(fname, sizeof(fname), "%s/passwd", configDir); } while (true) { diff --git a/unix/vncserver/vncserver.in b/unix/vncserver/vncserver.in index 95d672b17d..4f67489768 100755 --- a/unix/vncserver/vncserver.in +++ b/unix/vncserver/vncserver.in @@ -35,7 +35,15 @@ # your site # +# Start with legacy ~/.vnc user dir $vncUserDir = "$ENV{HOME}/.vnc"; +if (stat($vncUserDir)) { + warn "~/.vnc is deprecated, please migrate to XDGBDS-compliant paths!"; +} else { + # Legacy path doesn't exist, start using new XDG-alike path + $vncUserDir = "$ENV{HOME}/.config/tigervnc"; +} + $vncUserConfig = "$vncUserDir/config"; $vncSystemConfigDir = "@CMAKE_INSTALL_FULL_SYSCONFDIR@/tigervnc"; @@ -111,8 +119,8 @@ $default_opts{pn} = undef; # Load user-overrideable system defaults LoadConfig($vncSystemConfigDefaultsFile); -# Then the user's settings -LoadConfig($vncUserConfig); +# Then the user's settings (location overrideable by previous system defaults) +LoadConfig($config{'userconfig'} || $vncUserConfig); # And then override anything set above if mandatory settings exist. # WARNING: "Mandatory" is used loosely here! As the man page says, diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx index 6a76629509..4d57b5fbb9 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 75d46dcab8..15ea4ee80c 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 6eebf3d040..c5d6082ea6 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,14 @@ int main(int argc, char** argv) migrateDeprecatedOptions(); - mkvnchomedir(); +#ifndef WIN32 + // Check if config and state dirs are both the same legacy ~/.vnc dir + struct stat st; + if (stat(os::getvnchomedir(), &st) == 0) + vlog.info(_("~/.vnc is deprecated, please migrate to XDGBDS-compliant paths!")); +#endif + mkdirrecursive(os::getvncconfigdir()); + mkdirrecursive(os::getvncstatedir()); CSecurity::upg = &dlg; #if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE)