Merge pull request #1345 from p12tic/filesystem-cleanup

Filesystem operations cleanup
This commit is contained in:
Povilas Kanapickas 2021-11-01 04:47:16 +02:00 committed by GitHub
commit 6d7eca42b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 196 additions and 314 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "ext/gmock"] [submodule "ext/gmock"]
path = ext/gmock path = ext/gmock
url = https://github.com/google/googlemock.git url = https://github.com/google/googlemock.git
[submodule "ext/gulrak-filesystem"]
path = ext/gulrak-filesystem
url = https://github.com/gulrak/filesystem

View File

@ -301,6 +301,8 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
) )
endif() endif()
include_directories("${CMAKE_SOURCE_DIR}/ext/gulrak-filesystem/include")
# #
# OpenSSL # OpenSSL
# #

1
ext/gulrak-filesystem Submodule

@ -0,0 +1 @@
Subproject commit 614bbe87b80435d87ab8791564370e0c1d13627d

View File

@ -442,7 +442,7 @@ void MainWindow::checkFingerprint(const QString& line)
barrier::string::from_hex(fingerprintRegex.cap(2).toStdString()) barrier::string::from_hex(fingerprintRegex.cap(2).toStdString())
}; };
auto db_path = DataDirectories::trusted_servers_ssl_fingerprints_path(); auto db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path();
// We compare only SHA256 fingerprints, but show both SHA1 and SHA256 so that the users can // We compare only SHA256 fingerprints, but show both SHA1 and SHA256 so that the users can
// still verify fingerprints on old Barrier servers. This way the only time when we are exposed // still verify fingerprints on old Barrier servers. This way the only time when we are exposed
@ -564,7 +564,7 @@ void MainWindow::startBarrier()
// launched the process (e.g. when launched with elevation). setting the // launched the process (e.g. when launched with elevation). setting the
// profile dir on launch ensures it uses the same profile dir is used // profile dir on launch ensures it uses the same profile dir is used
// no matter how its relaunched. // no matter how its relaunched.
args << "--profile-dir" << QString::fromStdString("\"" + DataDirectories::profile() + "\""); args << "--profile-dir" << QString::fromStdString("\"" + barrier::DataDirectories::profile().u8string() + "\"");
#endif #endif
if ((barrierType() == barrierClient && !clientArgs(args, app)) if ((barrierType() == barrierClient && !clientArgs(args, app))
@ -1020,8 +1020,8 @@ void MainWindow::updateSSLFingerprint()
return; return;
} }
auto local_path = DataDirectories::local_ssl_fingerprints_path(); auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path();
if (!QFile::exists(QString::fromStdString(local_path))) { if (!barrier::fs::exists(local_path)) {
return; return;
} }

View File

@ -18,45 +18,36 @@
#include "SslCertificate.h" #include "SslCertificate.h"
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "base/finally.h" #include "base/finally.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include "net/FingerprintDatabase.h" #include "net/FingerprintDatabase.h"
#include "net/SecureUtils.h" #include "net/SecureUtils.h"
#include <QProcess>
#include <QDir>
#include <QCoreApplication>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/x509.h> #include <openssl/x509.h>
static const char kCertificateFilename[] = "Barrier.pem";
static const char kSslDir[] = "SSL";
SslCertificate::SslCertificate(QObject *parent) : SslCertificate::SslCertificate(QObject *parent) :
QObject(parent) QObject(parent)
{ {
m_ProfileDir = DataDirectories::profile(); if (barrier::DataDirectories::profile().empty()) {
if (m_ProfileDir.empty()) {
emit error(tr("Failed to get profile directory.")); emit error(tr("Failed to get profile directory."));
} }
} }
void SslCertificate::generateCertificate() void SslCertificate::generateCertificate()
{ {
auto cert_path = getCertificatePath(); auto cert_path = barrier::DataDirectories::ssl_certificate_path();
QFile file(QString::fromStdString(cert_path));
if (!file.exists() || !isCertificateValid(cert_path)) {
QDir sslDir(QString::fromStdString(getCertificateDirectory()));
if (!sslDir.exists()) {
sslDir.mkpath(".");
}
if (!barrier::fs::exists(cert_path) || !is_certificate_valid(cert_path)) {
try { try {
barrier::generate_pem_self_signed_cert(cert_path); auto cert_dir = cert_path.parent_path();
if (!barrier::fs::exists(cert_dir)) {
barrier::fs::create_directories(cert_dir);
}
barrier::generate_pem_self_signed_cert(cert_path.u8string());
} catch (const std::exception& e) { } catch (const std::exception& e) {
emit error(QString("SSL tool failed: %1").arg(e.what())); emit error(QString("SSL tool failed: %1").arg(e.what()));
return; return;
@ -65,19 +56,19 @@ void SslCertificate::generateCertificate()
emit info(tr("SSL certificate generated.")); emit info(tr("SSL certificate generated."));
} }
generateFingerprint(cert_path); generate_fingerprint(cert_path);
emit generateFinished(); emit generateFinished();
} }
void SslCertificate::generateFingerprint(const std::string& cert_path) void SslCertificate::generate_fingerprint(const barrier::fs::path& cert_path)
{ {
try { try {
auto local_path = DataDirectories::local_ssl_fingerprints_path(); auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path();
barrier::FingerprintDatabase db; barrier::FingerprintDatabase db;
db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path, db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
barrier::FingerprintType::SHA1)); barrier::FingerprintType::SHA1));
db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path, db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
barrier::FingerprintType::SHA256)); barrier::FingerprintType::SHA256));
db.write(local_path); db.write(local_path);
@ -87,17 +78,7 @@ void SslCertificate::generateFingerprint(const std::string& cert_path)
} }
} }
std::string SslCertificate::getCertificatePath() bool SslCertificate::is_certificate_valid(const barrier::fs::path& path)
{
return getCertificateDirectory() + QDir::separator().toLatin1() + kCertificateFilename;
}
std::string SslCertificate::getCertificateDirectory()
{
return m_ProfileDir + QDir::separator().toLatin1() + kSslDir;
}
bool SslCertificate::isCertificateValid(const std::string& path)
{ {
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
ERR_load_crypto_strings(); ERR_load_crypto_strings();

View File

@ -19,6 +19,7 @@
#include <QObject> #include <QObject>
#include <string> #include <string>
#include "io/filesystem.h"
class SslCertificate : public QObject class SslCertificate : public QObject
{ {
@ -36,13 +37,7 @@ signals:
void generateFinished(); void generateFinished();
private: private:
std::pair<bool, std::string> runTool(const QStringList& args); void generate_fingerprint(const barrier::fs::path& cert_path);
void generateFingerprint(const std::string& cert_path);
std::string getCertificatePath(); bool is_certificate_valid(const barrier::fs::path& path);
std::string getCertificateDirectory();
bool isCertificateValid(const std::string& path);
private:
std::string m_ProfileDir;
}; };

View File

@ -164,7 +164,7 @@ App::initApp(int argc, const char** argv)
// parse command line // parse command line
parseArgs(argc, argv); parseArgs(argc, argv);
DataDirectories::profile(argsBase().m_profileDirectory); barrier::DataDirectories::profile(argsBase().m_profileDirectory);
// set log filter // set log filter
if (!CLOG->setFilter(argsBase().m_logFilter)) { if (!CLOG->setFilter(argsBase().m_logFilter)) {

View File

@ -24,7 +24,7 @@
#include "barrier/ArgsBase.h" #include "barrier/ArgsBase.h"
#include "base/Log.h" #include "base/Log.h"
#include "base/String.h" #include "base/String.h"
#include "common/PathUtilities.h" #include "io/filesystem.h"
#ifdef WINAPI_MSWINDOWS #ifdef WINAPI_MSWINDOWS
#include <VersionHelpers.h> #include <VersionHelpers.h>
@ -288,10 +288,10 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
argsBase().m_enableCrypto = false; argsBase().m_enableCrypto = false;
} }
else if (isArg(i, argc, argv, NULL, "--profile-dir", 1)) { else if (isArg(i, argc, argv, NULL, "--profile-dir", 1)) {
argsBase().m_profileDirectory = argv[++i]; argsBase().m_profileDirectory = barrier::fs::u8path(argv[++i]);
} }
else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) { else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) {
argsBase().m_pluginDirectory = argv[++i]; argsBase().m_pluginDirectory = barrier::fs::u8path(argv[++i]);
} }
else { else {
// option not supported here // option not supported here
@ -487,7 +487,13 @@ void
ArgParser::updateCommonArgs(const char* const* argv) ArgParser::updateCommonArgs(const char* const* argv)
{ {
argsBase().m_name = ARCH->getHostName(); argsBase().m_name = ARCH->getHostName();
argsBase().m_exename = PathUtilities::basename(argv[0]); argsBase().m_exename = parse_exename(argv[0]);
}
std::string ArgParser::parse_exename(const char* arg)
{
// FIXME: we assume UTF-8 encoding, but on Windows this is not correct
return barrier::fs::u8path(arg).filename().u8string();
} }
bool bool

View File

@ -48,11 +48,14 @@ public:
static String assembleCommand(std::vector<String>& argsArray, static String assembleCommand(std::vector<String>& argsArray,
String ignoreArg = "", int parametersRequired = 0); String ignoreArg = "", int parametersRequired = 0);
static std::string parse_exename(const char* arg);
private: private:
void updateCommonArgs(const char* const* argv); void updateCommonArgs(const char* const* argv);
bool checkUnexpectedArgs(); bool checkUnexpectedArgs();
static ArgsBase& argsBase() { return *m_argsBase; } static ArgsBase& argsBase() { return *m_argsBase; }
bool parseMSWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i); bool parseMSWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
bool parseCarbonArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i); bool parseCarbonArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
bool parseXWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i); bool parseXWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);

View File

@ -43,7 +43,7 @@ m_dropTarget(""),
m_shouldExit(false), m_shouldExit(false),
m_barrierAddress(), m_barrierAddress(),
m_enableCrypto(true), m_enableCrypto(true),
m_profileDirectory(""), m_profileDirectory(),
m_pluginDirectory("") m_pluginDirectory("")
{ {
} }

View File

@ -19,6 +19,7 @@
#pragma once #pragma once
#include "base/String.h" #include "base/String.h"
#include "io/filesystem.h"
class ArgsBase { class ArgsBase {
public: public:
@ -50,6 +51,6 @@ public:
bool m_shouldExit; bool m_shouldExit;
String m_barrierAddress; String m_barrierAddress;
bool m_enableCrypto; bool m_enableCrypto;
String m_profileDirectory; barrier::fs::path m_profileDirectory;
String m_pluginDirectory; barrier::fs::path m_pluginDirectory;
}; };

View File

@ -40,7 +40,6 @@
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "base/Log.h" #include "base/Log.h"
#include "common/Version.h" #include "common/Version.h"
#include "common/PathUtilities.h"
#if WINAPI_MSWINDOWS #if WINAPI_MSWINDOWS
#include "platform/MSWindowsScreen.h" #include "platform/MSWindowsScreen.h"
@ -522,7 +521,7 @@ ClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc
{ {
// general initialization // general initialization
m_serverAddress = new NetworkAddress; m_serverAddress = new NetworkAddress;
args().m_exename = PathUtilities::basename(argv[0]); argsBase().m_exename = ArgParser::parse_exename(argv[0]);
// install caller's output filter // install caller's output filter
if (outputter != NULL) { if (outputter != NULL) {

View File

@ -18,7 +18,7 @@
#include "barrier/DropHelper.h" #include "barrier/DropHelper.h"
#include "base/Log.h" #include "base/Log.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include <fstream> #include <fstream>

View File

@ -40,7 +40,6 @@
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
#include "common/Version.h" #include "common/Version.h"
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "common/PathUtilities.h"
#if SYSAPI_WIN32 #if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h" #include "arch/win32/ArchMiscWindows.h"
@ -129,11 +128,15 @@ ServerApp::help()
#endif #endif
// refer to custom profile directory even if not saved yet // refer to custom profile directory even if not saved yet
String profilePath = argsBase().m_profileDirectory; barrier::fs::path profile_path = argsBase().m_profileDirectory;
if (profilePath.empty()) { if (profile_path.empty()) {
profilePath = DataDirectories::profile(); profile_path = barrier::DataDirectories::profile();
} }
auto usr_config_path = (profile_path / barrier::fs::u8path(USR_CONFIG_NAME)).u8string();
auto sys_config_path = (barrier::DataDirectories::systemconfig() /
barrier::fs::u8path(SYS_CONFIG_NAME)).u8string();
std::ostringstream buffer; std::ostringstream buffer;
buffer << "Start the barrier server component.\n" buffer << "Start the barrier server component.\n"
<< "\n" << "\n"
@ -156,8 +159,8 @@ ServerApp::help()
<< "\n" << "\n"
<< "If no configuration file pathname is provided then the first of the\n" << "If no configuration file pathname is provided then the first of the\n"
<< "following to load successfully sets the configuration:\n" << "following to load successfully sets the configuration:\n"
<< " " << PathUtilities::concat(profilePath, USR_CONFIG_NAME) << "\n" << " " << usr_config_path << "\n"
<< " " << PathUtilities::concat(DataDirectories::systemconfig(), SYS_CONFIG_NAME) << "\n"; << " " << sys_config_path << "\n";
LOG((CLOG_PRINT "%s", buffer.str().c_str())); LOG((CLOG_PRINT "%s", buffer.str().c_str()));
} }
@ -194,25 +197,25 @@ ServerApp::loadConfig()
// load the default configuration if no explicit file given // load the default configuration if no explicit file given
else { else {
String path = DataDirectories::profile(); auto path = barrier::DataDirectories::profile();
if (!path.empty()) { if (!path.empty()) {
// complete path // complete path
path = PathUtilities::concat(path, USR_CONFIG_NAME); path /= barrier::fs::u8path(USR_CONFIG_NAME);
// now try loading the user's configuration // now try loading the user's configuration
if (loadConfig(path)) { if (loadConfig(path.u8string())) {
loaded = true; loaded = true;
args().m_configFile = path; args().m_configFile = path.u8string();
} }
} }
if (!loaded) { if (!loaded) {
// try the system-wide config file // try the system-wide config file
path = DataDirectories::systemconfig(); path = barrier::DataDirectories::systemconfig();
if (!path.empty()) { if (!path.empty()) {
path = PathUtilities::concat(path, SYS_CONFIG_NAME); path /= barrier::fs::u8path(SYS_CONFIG_NAME);
if (loadConfig(path)) { if (loadConfig(path.u8string())) {
loaded = true; loaded = true;
args().m_configFile = path; args().m_configFile = path.u8string();
} }
} }
} }
@ -832,7 +835,7 @@ ServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc
// general initialization // general initialization
m_barrierAddress = new NetworkAddress; m_barrierAddress = new NetworkAddress;
args().m_config = new Config(m_events); args().m_config = new Config(m_events);
args().m_exename = PathUtilities::basename(argv[0]); args().m_exename = ArgParser::parse_exename(argv[0]);
// install caller's output filter // install caller's output filter
if (outputter != NULL) { if (outputter != NULL) {

View File

@ -245,7 +245,7 @@ DaemonApp::logFilename()
{ {
string logFilename = ARCH->setting("LogFilename"); string logFilename = ARCH->setting("LogFilename");
if (logFilename.empty()) if (logFilename.empty())
logFilename = DataDirectories::global() + "\\" + LOG_FILENAME; logFilename = (barrier::DataDirectories::global() / LOG_FILENAME).u8string();
MSWindowsUtil::createDirectory(logFilename, true); MSWindowsUtil::createDirectory(logFilename, true);
return logFilename; return logFilename;
} }

View File

@ -20,7 +20,7 @@
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "arch/Arch.h" #include "arch/Arch.h"
#include "base/String.h" #include "base/String.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include <fstream> #include <fstream>
enum EFileLogOutputter { enum EFileLogOutputter {

View File

@ -15,28 +15,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #ifndef BARRIER_LIB_COMMON_DATA_DIRECTORIES_H
#define BARRIER_LIB_COMMON_DATA_DIRECTORIES_H
#include <string> #include "io/filesystem.h"
namespace barrier {
class DataDirectories class DataDirectories
{ {
public: public:
static const std::string& profile(); static const fs::path& profile();
static const std::string& profile(const std::string& path); static const fs::path& profile(const fs::path& path);
static const std::string& global(); static const fs::path& global();
static const std::string& global(const std::string& path); static const fs::path& global(const fs::path& path);
static const std::string& systemconfig(); static const fs::path& systemconfig();
static const std::string& systemconfig(const std::string& path); static const fs::path& systemconfig(const fs::path& path);
static std::string ssl_fingerprints_path(); static fs::path ssl_fingerprints_path();
static std::string local_ssl_fingerprints_path(); static fs::path local_ssl_fingerprints_path();
static std::string trusted_servers_ssl_fingerprints_path(); static fs::path trusted_servers_ssl_fingerprints_path();
static std::string trusted_clients_ssl_fingerprints_path(); static fs::path trusted_clients_ssl_fingerprints_path();
static fs::path ssl_certificate_path();
private: private:
static std::string _profile; static fs::path _profile;
static std::string _global; static fs::path _global;
static std::string _systemconfig; static fs::path _systemconfig;
}; };
} // namespace barrier
#endif

View File

@ -17,32 +17,40 @@
#include "DataDirectories.h" #include "DataDirectories.h"
// static member namespace barrier {
std::string DataDirectories::_profile;
std::string DataDirectories::_global; fs::path DataDirectories::_profile;
std::string DataDirectories::_systemconfig; fs::path DataDirectories::_global;
fs::path DataDirectories::_systemconfig;
static const char kFingerprintsDirName[] = "SSL/Fingerprints"; static const char kFingerprintsDirName[] = "SSL/Fingerprints";
static const char kFingerprintsLocalFilename[] = "Local.txt"; static const char kFingerprintsLocalFilename[] = "Local.txt";
static const char kFingerprintsTrustedServersFilename[] = "TrustedServers.txt"; static const char kFingerprintsTrustedServersFilename[] = "TrustedServers.txt";
static const char kFingerprintsTrustedClientsFilename[] = "TrustedClients.txt"; static const char kFingerprintsTrustedClientsFilename[] = "TrustedClients.txt";
std::string DataDirectories::ssl_fingerprints_path() fs::path DataDirectories::ssl_fingerprints_path()
{ {
return profile() + "/" + kFingerprintsDirName; return profile() / kFingerprintsDirName;
} }
std::string DataDirectories::local_ssl_fingerprints_path() fs::path DataDirectories::local_ssl_fingerprints_path()
{ {
return ssl_fingerprints_path() + "/" + kFingerprintsLocalFilename; return ssl_fingerprints_path() / kFingerprintsLocalFilename;
} }
std::string DataDirectories::trusted_servers_ssl_fingerprints_path() fs::path DataDirectories::trusted_servers_ssl_fingerprints_path()
{ {
return ssl_fingerprints_path() + "/" + kFingerprintsTrustedServersFilename; return ssl_fingerprints_path() / kFingerprintsTrustedServersFilename;
} }
std::string DataDirectories::trusted_clients_ssl_fingerprints_path() fs::path DataDirectories::trusted_clients_ssl_fingerprints_path()
{ {
return ssl_fingerprints_path() + "/" + kFingerprintsTrustedClientsFilename; return ssl_fingerprints_path() / kFingerprintsTrustedClientsFilename;
} }
fs::path DataDirectories::ssl_certificate_path()
{
return profile() / "SSL" / "Barrier.pem";
}
} // namespace barrier

View File

@ -1,23 +0,0 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
//
// Prefix header for all source files of the 'deleteme' target in the 'deleteme' project.
//
#include <Carbon/Carbon.h>

View File

@ -1,75 +0,0 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2018 Debauchee Open Source Group
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
These functions cover the vast majority of cases for different paths across
windows and unixes. They are not, however, fullproof and probably don't cover
fringe cases very well. The library below might be used as an alternative if
these implementations prove to be insufficient. As the library's readme states
it is simply a temporary band-aid until std::filesystem is integrated (C++17
has it in std::experimental) and this class should also be treated as such.
https://github.com/wjakob/filesystem/
*/
#include "PathUtilities.h"
// keep the default platform delimiter as the first in the list
#ifdef _WIN32
static const char *Delimiters = "\\/";
#else
static const char *Delimiters = "/";
#endif
static const char DefaultDelimiter = Delimiters[0];
std::string PathUtilities::basename(const std::string& path)
{
return path.substr(path.find_last_of(Delimiters) + 1);
}
std::string PathUtilities::concat(const std::string& left, const std::string& right)
{
// although npos is usually (-1) we can't count on that so handle it explicitly
auto leftEnd = left.find_last_not_of(Delimiters);
if (leftEnd == std::string::npos)
leftEnd = 0;
else
++leftEnd;
auto rightStart = right.find_first_not_of(Delimiters, 0);
if (rightStart == std::string::npos) {
// both left/right are empty
if (left.size() == 0 && right.size() == 0)
return "";
// right is full of delims, left is okay
if (leftEnd > 0)
return left.substr(0, leftEnd);
// both left/right useless but at least one has delims
return std::string(1, DefaultDelimiter);
}
if (leftEnd == 0) {
// right is okay and not prefixed with delims, left is empty
if (left.size() == 0 && rightStart == 0)
return right.substr(rightStart);
// (right is okay and prefixed with delims) OR left is full of delims
return DefaultDelimiter + right.substr(rightStart);
}
// concatenation using both left and right
return left.substr(0, leftEnd) + DefaultDelimiter + right.substr(rightStart);
}

View File

@ -1,27 +0,0 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2018 Debauchee Open Source Group
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
class PathUtilities
{
public:
static std::string basename(const std::string& path);
static std::string concat(const std::string& left, const std::string& right);
};

View File

@ -22,7 +22,7 @@
#include <sys/types.h> // getpwuid(_r) #include <sys/types.h> // getpwuid(_r)
#include <pwd.h> // getpwuid(_r) #include <pwd.h> // getpwuid(_r)
const std::string ProfileSubdir = "/barrier"; namespace barrier {
static std::string pw_dir(struct passwd* pwentp) static std::string pw_dir(struct passwd* pwentp)
{ {
@ -33,7 +33,7 @@ static std::string pw_dir(struct passwd* pwentp)
#ifdef HAVE_GETPWUID_R #ifdef HAVE_GETPWUID_R
static std::string unix_home() static fs::path unix_home()
{ {
long size = -1; long size = -1;
#if defined(_SC_GETPW_R_SIZE_MAX) #if defined(_SC_GETPW_R_SIZE_MAX)
@ -46,47 +46,47 @@ static std::string unix_home()
struct passwd* pwentp; struct passwd* pwentp;
std::string buffer(size, 0); std::string buffer(size, 0);
getpwuid_r(getuid(), &pwent, &buffer[0], size, &pwentp); getpwuid_r(getuid(), &pwent, &buffer[0], size, &pwentp);
return pw_dir(pwentp); return fs::u8path(pw_dir(pwentp));
} }
#else // not HAVE_GETPWUID_R #else // not HAVE_GETPWUID_R
static std::string unix_home() static fs::path unix_home()
{ {
return pw_dir(getpwuid(getuid())); return fs::u8path(pw_dir(getpwuid(getuid())));
} }
#endif // HAVE_GETPWUID_R #endif // HAVE_GETPWUID_R
static std::string profile_basedir() static fs::path profile_basedir()
{ {
#ifdef WINAPI_XWINDOWS #ifdef WINAPI_XWINDOWS
// linux/bsd adheres to freedesktop standards // linux/bsd adheres to freedesktop standards
// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
const char* dir = std::getenv("XDG_DATA_HOME"); const char* dir = std::getenv("XDG_DATA_HOME");
if (dir != NULL) if (dir != NULL)
return dir; return fs::u8path(dir);
return unix_home() + "/.local/share"; return unix_home() / ".local/share";
#else #else
// macos has its own standards // macos has its own standards
// https://developer.apple.com/library/content/documentation/General/Conceptual/MOSXAppProgrammingGuide/AppRuntime/AppRuntime.html // https://developer.apple.com/library/content/documentation/General/Conceptual/MOSXAppProgrammingGuide/AppRuntime/AppRuntime.html
return unix_home() + "/Library/Application Support"; return unix_home() / "Library/Application Support";
#endif #endif
} }
const std::string& DataDirectories::profile() const fs::path& DataDirectories::profile()
{ {
if (_profile.empty()) if (_profile.empty())
_profile = profile_basedir() + ProfileSubdir; _profile = profile_basedir() / "barrier";
return _profile; return _profile;
} }
const std::string& DataDirectories::profile(const std::string& path) const fs::path& DataDirectories::profile(const fs::path& path)
{ {
_profile = path; _profile = path;
return _profile; return _profile;
} }
const std::string& DataDirectories::global() const fs::path& DataDirectories::global()
{ {
if (_global.empty()) if (_global.empty())
// TODO: where on a unix system should public/global shared data go? // TODO: where on a unix system should public/global shared data go?
@ -94,21 +94,23 @@ const std::string& DataDirectories::global()
_global = "/tmp"; _global = "/tmp";
return _global; return _global;
} }
const std::string& DataDirectories::global(const std::string& path) const fs::path& DataDirectories::global(const fs::path& path)
{ {
_global = path; _global = path;
return _global; return _global;
} }
const std::string& DataDirectories::systemconfig() const fs::path& DataDirectories::systemconfig()
{ {
if (_systemconfig.empty()) if (_systemconfig.empty())
_systemconfig = "/etc"; _systemconfig = "/etc";
return _systemconfig; return _systemconfig;
} }
const std::string& DataDirectories::systemconfig(const std::string& path) const fs::path& DataDirectories::systemconfig(const fs::path& path)
{ {
_systemconfig = path; _systemconfig = path;
return _systemconfig; return _systemconfig;
} }
} // namespace barrier

View File

@ -20,43 +20,45 @@
#include <Shlobj.h> #include <Shlobj.h>
std::string known_folder_path(const KNOWNFOLDERID& id) namespace barrier {
fs::path known_folder_path(const KNOWNFOLDERID& id)
{ {
std::string path; fs::path path;
WCHAR* buffer; WCHAR* buffer;
HRESULT result = SHGetKnownFolderPath(id, 0, NULL, &buffer); HRESULT result = SHGetKnownFolderPath(id, 0, NULL, &buffer);
if (result == S_OK) { if (result == S_OK) {
path = win_wchar_to_utf8(buffer); path = fs::path(std::wstring(buffer));
CoTaskMemFree(buffer); CoTaskMemFree(buffer);
} }
return path; return path;
} }
const std::string& DataDirectories::profile() const fs::path& DataDirectories::profile()
{ {
if (_profile.empty()) if (_profile.empty())
_profile = known_folder_path(FOLDERID_LocalAppData) + "\\Barrier"; _profile = known_folder_path(FOLDERID_LocalAppData) / "Barrier";
return _profile; return _profile;
} }
const std::string& DataDirectories::profile(const std::string& path) const fs::path& DataDirectories::profile(const fs::path& path)
{ {
_profile = path; _profile = path;
return _profile; return _profile;
} }
const std::string& DataDirectories::global() const fs::path& DataDirectories::global()
{ {
if (_global.empty()) if (_global.empty())
_global = known_folder_path(FOLDERID_ProgramData) + "\\Barrier"; _global = known_folder_path(FOLDERID_ProgramData) / "Barrier";
return _global; return _global;
} }
const std::string& DataDirectories::global(const std::string& path) const fs::path& DataDirectories::global(const fs::path& path)
{ {
_global = path; _global = path;
return _global; return _global;
} }
const std::string& DataDirectories::systemconfig() const fs::path& DataDirectories::systemconfig()
{ {
// systemconfig() is a special case in that it will track the current value // systemconfig() is a special case in that it will track the current value
// of global() unless and until it is explicitly set otherwise // of global() unless and until it is explicitly set otherwise
@ -66,8 +68,10 @@ const std::string& DataDirectories::systemconfig()
return _systemconfig; return _systemconfig;
} }
const std::string& DataDirectories::systemconfig(const std::string& path) const fs::path& DataDirectories::systemconfig(const fs::path& path)
{ {
_systemconfig = path; _systemconfig = path;
return _systemconfig; return _systemconfig;
} }
} // namespace barrier

View File

@ -15,7 +15,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "fstream.h" // this header must come first so that it picks up the filesystem implementation
#include <ghc/fs_impl.hpp>
#include "filesystem.h"
#if SYSAPI_WIN32 #if SYSAPI_WIN32
#include "common/win32/encoding_utilities.h" #include "common/win32/encoding_utilities.h"
#endif #endif
@ -26,43 +29,42 @@ namespace barrier {
namespace { namespace {
template<class Stream> template<class Stream>
void open_utf8_path_impl(Stream& stream, const std::string& path, std::ios_base::openmode mode) void open_utf8_path_impl(Stream& stream, const fs::path& path, std::ios_base::openmode mode)
{ {
#if SYSAPI_WIN32 #if SYSAPI_WIN32
// on Windows we need to use a private constructor from wchar_t* string. // on Windows we need to use a non-standard constructor from wchar_t* string
auto wchar_path = utf8_to_win_char(path); // which fs::path::native() returns
stream.open(wchar_path.data(), mode); stream.open(path.native().c_str(), mode);
#else #else
stream.open(path.c_str(), mode); stream.open(path.native().c_str(), mode);
#endif #endif
} }
} // namespace } // namespace
void open_utf8_path(std::ifstream& stream, const std::string& path, std::ios_base::openmode mode) void open_utf8_path(std::ifstream& stream, const fs::path& path, std::ios_base::openmode mode)
{ {
open_utf8_path_impl(stream, path, mode); open_utf8_path_impl(stream, path, mode);
} }
void open_utf8_path(std::ofstream& stream, const std::string& path, std::ios_base::openmode mode) void open_utf8_path(std::ofstream& stream, const fs::path& path, std::ios_base::openmode mode)
{ {
open_utf8_path_impl(stream, path, mode); open_utf8_path_impl(stream, path, mode);
} }
void open_utf8_path(std::fstream& stream, const std::string& path, std::ios_base::openmode mode) void open_utf8_path(std::fstream& stream, const fs::path& path, std::ios_base::openmode mode)
{ {
open_utf8_path_impl(stream, path, mode); open_utf8_path_impl(stream, path, mode);
} }
std::FILE* fopen_utf8_path(const std::string& path, const std::string& mode) std::FILE* fopen_utf8_path(const fs::path& path, const std::string& mode)
{ {
#if SYSAPI_WIN32 #if SYSAPI_WIN32
auto wchar_path = utf8_to_win_char(path);
auto wchar_mode = utf8_to_win_char(mode); auto wchar_mode = utf8_to_win_char(mode);
return _wfopen(reinterpret_cast<wchar_t*>(wchar_path.data()), return _wfopen(path.native().c_str(),
reinterpret_cast<wchar_t*>(wchar_mode.data())); reinterpret_cast<wchar_t*>(wchar_mode.data()));
#else #else
return std::fopen(path.c_str(), mode.c_str()); return std::fopen(path.native().c_str(), mode.c_str());
#endif #endif
} }

View File

@ -15,24 +15,27 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef BARRIER_LIB_IO_FSTREAM_H #ifndef BARRIER_LIB_IO_FILESYSTEM_H
#define BARRIER_LIB_IO_FSTREAM_H #define BARRIER_LIB_IO_FILESYSTEM_H
#include <cstdio> #include <cstdio>
#include <iosfwd> #include <iosfwd>
#include <ios> #include <ios>
#include <ghc/fs_fwd.hpp>
namespace barrier { namespace barrier {
void open_utf8_path(std::ifstream& stream, const std::string& path, namespace fs = ghc::filesystem;
void open_utf8_path(std::ifstream& stream, const fs::path& path,
std::ios_base::openmode mode = std::ios_base::in); std::ios_base::openmode mode = std::ios_base::in);
void open_utf8_path(std::ofstream& stream, const std::string& path, void open_utf8_path(std::ofstream& stream, const fs::path& path,
std::ios_base::openmode mode = std::ios_base::out); std::ios_base::openmode mode = std::ios_base::out);
void open_utf8_path(std::fstream& stream, const std::string& path, void open_utf8_path(std::fstream& stream, const fs::path& path,
std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out); std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
std::FILE* fopen_utf8_path(const std::string& path, const std::string& mode); std::FILE* fopen_utf8_path(const fs::path& path, const std::string& mode);
} // namespace barrier } // namespace barrier
#endif #endif // BARRIER_LIB_IO_FILESYSTEM_H

View File

@ -17,7 +17,7 @@
#include "base/String.h" #include "base/String.h"
#include "FingerprintDatabase.h" #include "FingerprintDatabase.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>

View File

@ -17,20 +17,20 @@
#include "base/String.h" #include "base/String.h"
#include "FingerprintDatabase.h" #include "FingerprintDatabase.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
namespace barrier { namespace barrier {
void FingerprintDatabase::read(const std::string& path) void FingerprintDatabase::read(const fs::path& path)
{ {
std::ifstream file; std::ifstream file;
open_utf8_path(file, path, std::ios_base::in); open_utf8_path(file, path, std::ios_base::in);
read_stream(file); read_stream(file);
} }
void FingerprintDatabase::write(const std::string& path) void FingerprintDatabase::write(const fs::path& path)
{ {
std::ofstream file; std::ofstream file;
open_utf8_path(file, path, std::ios_base::out); open_utf8_path(file, path, std::ios_base::out);

View File

@ -19,6 +19,7 @@
#define BARRIER_LIB_NET_FINGERPRINT_DATABASE_H #define BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
#include "FingerprintData.h" #include "FingerprintData.h"
#include "io/filesystem.h"
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <vector> #include <vector>
@ -27,8 +28,8 @@ namespace barrier {
class FingerprintDatabase { class FingerprintDatabase {
public: public:
void read(const std::string& path); void read(const fs::path& path);
void write(const std::string& path); void write(const fs::path& path);
void read_stream(std::istream& stream); void read_stream(std::istream& stream);
void write_stream(std::ostream& stream); void write_stream(std::ostream& stream);

View File

@ -25,13 +25,6 @@
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "base/String.h" #include "base/String.h"
static const char s_certificateDir[] = { "SSL" };
static const char s_certificateFilename[] = { "Barrier.pem" };
//
// SecureListenSocket
//
SecureListenSocket::SecureListenSocket( SecureListenSocket::SecureListenSocket(
IEventQueue* events, IEventQueue* events,
SocketMultiplexer* socketMultiplexer, SocketMultiplexer* socketMultiplexer,
@ -55,12 +48,7 @@ SecureListenSocket::accept()
setListeningJob(); setListeningJob();
} }
std::string certificateFilename = barrier::string::sprintf("%s/%s/%s", bool loaded = socket->load_certificates(barrier::DataDirectories::ssl_certificate_path());
DataDirectories::profile().c_str(),
s_certificateDir,
s_certificateFilename);
bool loaded = socket->loadCertificates(certificateFilename);
if (!loaded) { if (!loaded) {
delete socket; delete socket;
return NULL; return NULL;

View File

@ -26,7 +26,7 @@
#include "base/Log.h" #include "base/Log.h"
#include "base/String.h" #include "base/String.h"
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include "net/FingerprintDatabase.h" #include "net/FingerprintDatabase.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
@ -327,39 +327,35 @@ SecureSocket::initSsl(bool server)
initContext(server); initContext(server);
} }
bool SecureSocket::loadCertificates(const std::string& filename) bool SecureSocket::load_certificates(const barrier::fs::path& path)
{ {
if (filename.empty()) { if (path.empty()) {
showError("ssl certificate is not specified"); showError("ssl certificate is not specified");
return false; return false;
} }
else { else {
std::ifstream file(filename.c_str()); if (!barrier::fs::is_regular_file(path)) {
bool exist = file.good(); showError("ssl certificate doesn't exist: " + path.u8string());
file.close();
if (!exist) {
showError("ssl certificate doesn't exist: " + filename);
return false; return false;
} }
} }
int r = 0; int r = 0;
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); r = SSL_CTX_use_certificate_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) { if (r <= 0) {
showError("could not use ssl certificate: " + filename); showError("could not use ssl certificate: " + path.u8string());
return false; return false;
} }
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) { if (r <= 0) {
showError("could not use ssl private key: " + filename); showError("could not use ssl private key: " + path.u8string());
return false; return false;
} }
r = SSL_CTX_check_private_key(m_ssl->m_context); r = SSL_CTX_check_private_key(m_ssl->m_context);
if (!r) { if (!r) {
showError("could not verify ssl private key: " + filename); showError("could not verify ssl private key: " + path.u8string());
return false; return false;
} }
@ -674,20 +670,20 @@ SecureSocket::verifyCertFingerprint()
barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(), barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(),
barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str())); barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str()));
auto fingerprint_db_path = DataDirectories::trusted_servers_ssl_fingerprints_path(); auto fingerprint_db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path();
// Provide debug hint as to what file is being used to verify fingerprint trust // Provide debug hint as to what file is being used to verify fingerprint trust
LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.c_str())); LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));
barrier::FingerprintDatabase db; barrier::FingerprintDatabase db;
db.read(fingerprint_db_path); db.read(fingerprint_db_path);
if (!db.fingerprints().empty()) { if (!db.fingerprints().empty()) {
LOG((CLOG_NOTE "Read %d fingerprints from: %s", db.fingerprints().size(), LOG((CLOG_NOTE "Read %d fingerprints from: %s", db.fingerprints().size(),
fingerprint_db_path.c_str())); fingerprint_db_path.u8string().c_str()));
} else { } else {
LOG((CLOG_NOTE "Could not read fingerprints from: %s", LOG((CLOG_NOTE "Could not read fingerprints from: %s",
fingerprint_db_path.c_str())); fingerprint_db_path.u8string().c_str()));
} }
if (db.is_trusted(fingerprint_sha256)) { if (db.is_trusted(fingerprint_sha256)) {

View File

@ -19,6 +19,7 @@
#include "net/TCPSocket.h" #include "net/TCPSocket.h"
#include "net/XSocket.h" #include "net/XSocket.h"
#include "io/filesystem.h"
class IEventQueue; class IEventQueue;
class SocketMultiplexer; class SocketMultiplexer;
@ -55,7 +56,7 @@ public:
EJobResult doRead() override; EJobResult doRead() override;
EJobResult doWrite() override; EJobResult doWrite() override;
void initSsl(bool server); void initSsl(bool server);
bool loadCertificates(const std::string& filename); bool load_certificates(const barrier::fs::path& path);
private: private:
// SSL // SSL

View File

@ -46,7 +46,7 @@
#include "SecureUtils.h" #include "SecureUtils.h"
#include "base/String.h" #include "base/String.h"
#include "base/finally.h" #include "base/finally.h"
#include "io/fstream.h" #include "io/filesystem.h"
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/x509.h> #include <openssl/x509.h>

View File

@ -574,7 +574,7 @@ MSWindowsHook::install()
g_fakeServerInput = false; g_fakeServerInput = false;
// setup immune keys // setup immune keys
g_immuneKeysPath = DataDirectories::profile() + "\\ImmuneKeys.txt"; g_immuneKeysPath = (barrier::DataDirectories::profile() / "ImmuneKeys.txt").u8string();
g_immuneKeys = immune_keys_list(); g_immuneKeys = immune_keys_list();
LOG((CLOG_DEBUG "Found %u immune keys in %s", g_immuneKeys.size(), g_immuneKeysPath.c_str())); LOG((CLOG_DEBUG "Found %u immune keys in %s", g_immuneKeys.size(), g_immuneKeysPath.c_str()));