Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for alternative user config locations, deprecate ~/.vnc in favour of XDG Base Directory Specification paths #1737

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ CMakeCache.txt
Makefile
Makefile.in
config.h
cmake_install.cmake
cmake_uninstall.cmake
install_manifest.txt
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably best to have all CMake generated files in the same place.

52 changes: 39 additions & 13 deletions common/os/os.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,30 @@
#include <os/os.h>

#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifndef WIN32
#include <pwd.h>
#include <limits.h>
#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
Expand All @@ -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
Expand All @@ -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");
}
34 changes: 28 additions & 6 deletions common/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

}

Expand Down
27 changes: 13 additions & 14 deletions common/rfb/CSecurityTLS.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
# Option "PasswordFile" "/root/.vnc/passwd"
# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
2 changes: 1 addition & 1 deletion contrib/packages/rpm/el8/SOURCES/10-libvnc.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
# Option "PasswordFile" "/root/.vnc/passwd"
# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
2 changes: 1 addition & 1 deletion contrib/packages/rpm/el9/SOURCES/10-libvnc.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
# Identifier "Screen0
# DefaultDepth 16
# Option "SecurityTypes" "VncAuth"
# Option "PasswordFile" "/root/.vnc/passwd"
# Option "PasswordFile" "/root/.config/tigervnc/passwd"
#EndSection
4 changes: 4 additions & 0 deletions java/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.class
*.jar
.idea/
timestamp
9 changes: 4 additions & 5 deletions java/com/tigervnc/rfb/CSecurityTLS.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ public CSecurityTLS(boolean _anon)
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()
Expand Down Expand Up @@ -277,12 +277,12 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
"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");
}
}
Expand Down Expand Up @@ -356,7 +356,6 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
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);
Expand Down
48 changes: 38 additions & 10 deletions java/com/tigervnc/vncviewer/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

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");
Expand Down Expand Up @@ -56,21 +58,47 @@ public static final String getHomeDir() {
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);
Expand Down
18 changes: 1 addition & 17 deletions java/com/tigervnc/vncviewer/Parameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,6 @@ public static void saveViewerParameters(String filename, String servername) {
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;
}
Expand Down Expand Up @@ -385,16 +378,7 @@ public static String loadViewerParameters(String filename) throws Exception {

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;
}
Expand Down
Loading