diff --git a/dDashboardServer/routes/BackupFiles.cpp b/dDashboardServer/routes/BackupFiles.cpp index 189190547..7bc888ab4 100644 --- a/dDashboardServer/routes/BackupFiles.cpp +++ b/dDashboardServer/routes/BackupFiles.cpp @@ -116,16 +116,33 @@ namespace BackupFiles { } std::vector MysqldumpArguments(const DumpCommand& command) { + // mysql_host as the servers read it (MySQLDatabase::Connect): host, host:port, tcp://host:port, unix://socket or pipe://name auto host = command.host; std::string port; - if (const auto colon = host.find(':'); colon != std::string::npos) { - port = host.substr(colon + 1); - host = host.substr(0, colon); + std::string socket; + bool pipe = false; + if (host.starts_with("unix://")) { + socket = host.substr(7); + host.clear(); + } else if (host.starts_with("pipe://")) { + socket = host.substr(7); + pipe = true; + host.clear(); + } else { + if (host.starts_with("tcp://")) host = host.substr(6); + // A database after the address (tcp://host:port/db) is not the host's; mysql_database names it + if (const auto slash = host.find('/'); slash != std::string::npos) host.resize(slash); + if (const auto colon = host.find(':'); colon != std::string::npos) { + port = host.substr(colon + 1); + host = host.substr(0, colon); + } } std::vector arguments{ command.program, "--defaults-extra-file=" + command.optionsFile, "--single-transaction", "--quick", "--routines", "--triggers", "--hex-blob", "--no-tablespaces", "--default-character-set=utf8mb4" }; if (!host.empty()) arguments.push_back("--host=" + host); if (!port.empty()) arguments.push_back("--port=" + port); + if (pipe) arguments.push_back("--protocol=PIPE"); + if (!socket.empty()) arguments.push_back("--socket=" + socket); arguments.push_back("--result-file=" + command.target); if (!command.errorFile.empty()) arguments.push_back("--log-error=" + command.errorFile); arguments.push_back(command.database); diff --git a/dDashboardServer/routes/BackupFiles.h b/dDashboardServer/routes/BackupFiles.h index ce0d7bcb5..b8582098d 100644 --- a/dDashboardServer/routes/BackupFiles.h +++ b/dDashboardServer/routes/BackupFiles.h @@ -39,7 +39,7 @@ namespace BackupFiles { struct DumpCommand { std::string program; std::string optionsFile; - std::string host; // host or host:port + std::string host; // mysql_host: host, host:port, tcp://host:port, unix://socket or pipe://name std::string database; std::string target; std::string errorFile; // mysqldump's messages; never mixed into the dump, where they would break a restore diff --git a/tests/dWebTests/SecurityFixesTests.cpp b/tests/dWebTests/SecurityFixesTests.cpp index 1149388a3..7b2b355fb 100644 --- a/tests/dWebTests/SecurityFixesTests.cpp +++ b/tests/dWebTests/SecurityFixesTests.cpp @@ -121,3 +121,32 @@ TEST(BackupFilesTests, MysqldumpArgumentsAreAVector) { // Passed as one literal argument, never interpreted EXPECT_EQ(arguments.back(), "dlu$(touch x)"); } + +// mysql_host in every form the servers connect with +TEST(BackupFilesTests, MysqldumpArgumentsReadEveryHostForm) { + const auto has = [](const std::vector& arguments, const std::string& argument) { + return std::find(arguments.begin(), arguments.end(), argument) != arguments.end(); + }; + const auto dump = [](const std::string& host) { return BackupFiles::MysqldumpArguments({ "mysqldump", "/tmp/opt", host, "dlu", "/b/x", "" }); }; + + auto arguments = dump("tcp://10.0.0.5:3307"); + EXPECT_TRUE(has(arguments, "--host=10.0.0.5")); + EXPECT_TRUE(has(arguments, "--port=3307")); + + arguments = dump("tcp://db.local:3306/dlu"); + EXPECT_TRUE(has(arguments, "--host=db.local")); + EXPECT_TRUE(has(arguments, "--port=3306")); + + arguments = dump("db.local"); + EXPECT_TRUE(has(arguments, "--host=db.local")); + EXPECT_FALSE(std::any_of(arguments.begin(), arguments.end(), [](const std::string& a) { return a.starts_with("--port="); })); + + arguments = dump("unix:///run/mysqld/mysqld.sock"); + EXPECT_TRUE(has(arguments, "--socket=/run/mysqld/mysqld.sock")); + EXPECT_FALSE(std::any_of(arguments.begin(), arguments.end(), [](const std::string& a) { return a.starts_with("--host=") || a.starts_with("--port="); })); + + arguments = dump("pipe://MySQL"); + EXPECT_TRUE(has(arguments, "--protocol=PIPE")); + EXPECT_TRUE(has(arguments, "--socket=MySQL")); + EXPECT_EQ(arguments.back(), "dlu"); +}