diff options
author | Chris Wilson <chris+github@qwirx.com> | 2014-09-18 20:28:58 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2014-09-18 20:28:58 +0000 |
commit | f244fb5f61f764ab2aff76b0b1b9d85e8ea1e751 (patch) | |
tree | 2d647f99e09ae631cfd91fd3c7b76e3c378578ef | |
parent | 172fcf113f39d79b074f0c28f30aa96329a7390a (diff) |
Fix inability to access locations starting with a slash.
Thanks to Jean-Yves Moulin for reporting this issue. When bbackupd is configured
to create locations whose names contain a slash, it was impossible to escape it,
and thus to enter the directory in bbackupquery to inspect or restore it.
-rw-r--r-- | lib/common/Utils.cpp | 37 | ||||
-rw-r--r-- | lib/common/Utils.h | 2 | ||||
-rw-r--r-- | test/bbackupd/testbbackupd.cpp | 64 |
3 files changed, 83 insertions, 20 deletions
diff --git a/lib/common/Utils.cpp b/lib/common/Utils.cpp index f3541648..ddb79ba8 100644 --- a/lib/common/Utils.cpp +++ b/lib/common/Utils.cpp @@ -51,25 +51,40 @@ std::string GetBoxBackupVersion() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void SplitString(const std::string &String, char SplitOn, std::vector<std::string> &rOutput) +void SplitString(std::string String, char SplitOn, std::vector<std::string> &rOutput) { // Split it up. - std::string::size_type b = 0; - std::string::size_type e = 0; - while(e = String.find_first_of(SplitOn, b), e != String.npos) + std::string::size_type begin = 0, end = 0, pos = 0; + + while(end = String.find_first_of(SplitOn, pos), end != String.npos) { - // Get this string - unsigned int len = e - b; - if(len >= 1) + // Is it preceded by the escape character? + if(end > 0 && String[end - 1] == '\\') + { + // Ignore this one, don't change begin, let the next + // match/fallback consume it instead. But remove the + // backslash from the string, and set pos to the + // current position, which no longer contains a + // separator character. + String.erase(end - 1, 1); + pos = end; + } + else { - rOutput.push_back(String.substr(b, len)); + // Extract the substring and move past it. + unsigned int len = end - begin; + if(len >= 1) + { + rOutput.push_back(String.substr(begin, len)); + } + begin = end + 1; + pos = begin; } - b = e + 1; } // Last string - if(b < String.size()) + if(begin < String.size()) { - rOutput.push_back(String.substr(b)); + rOutput.push_back(String.substr(begin)); } /*#ifndef BOX_RELEASE_BUILD BOX_TRACE("Splitting string '" << String << " on " << (char)SplitOn); diff --git a/lib/common/Utils.h b/lib/common/Utils.h index 3134245a..636fb487 100644 --- a/lib/common/Utils.h +++ b/lib/common/Utils.h @@ -17,7 +17,7 @@ std::string GetBoxBackupVersion(); -void SplitString(const std::string &String, char SplitOn, std::vector<std::string> &rOutput); +void SplitString(std::string String, char SplitOn, std::vector<std::string> &rOutput); #ifdef SHOW_BACKTRACE_ON_EXCEPTION void DumpStackBacktrace(); diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index d85d2595..52ec9254 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1013,15 +1013,24 @@ bool compare(BackupQueries::ReturnCode::Type expected_status, return (returnValue == expected_system_result); } -bool compare_local(BackupQueries::ReturnCode::Type expected_status, - BackupProtocolCallable& client, - const std::string& compare_options = "acQ") +std::auto_ptr<Configuration> load_config_file( + std::string config_file = "testfiles/bbackupd.conf") { std::string errs; std::auto_ptr<Configuration> config( Configuration::LoadAndVerify ("testfiles/bbackupd.conf", &BackupDaemonConfigVerify, errs)); - TEST_EQUAL_OR(0, errs.size(), return false); + TEST_EQUAL_LINE(0, errs.size(), "Failed to load configuration file: " + errs); + TEST_EQUAL_OR(0, errs.size(), config.reset()); + return config; +} + +bool compare_local(BackupQueries::ReturnCode::Type expected_status, + BackupProtocolCallable& client, + const std::string& compare_options = "acQ") +{ + std::auto_ptr<Configuration> config = load_config_file(); + TEST_THAT_OR(config.get(), return false); BackupQueries bbackupquery(client, *config, false); std::vector<std::string> args; @@ -1184,15 +1193,53 @@ bool test_readdirectory_on_nonexistent_dir() TEARDOWN(); } +bool test_bbackupquery_parser_escape_slashes() +{ + SETUP_WITH_BBSTORED(); + + BackupProtocolLocal2 connection(0x01234567, "test", + "backup/01234567/", 0, false); + + BackupClientFileAttributes attr; + attr.ReadAttributes("testfiles/TestDir1", + false /* put mod times in the attributes, please */); + std::auto_ptr<IOStream> attrStream(new MemBlockStream(attr)); + BackupStoreFilenameClear dirname("foo"); + int64_t foo_id = connection.QueryCreateDirectory( + BACKUPSTORE_ROOT_DIRECTORY_ID, // containing directory + 0, // attrModTime, + dirname, // dirname, + attrStream)->GetObjectID(); + + attrStream.reset(new MemBlockStream(attr)); + dirname = BackupStoreFilenameClear("/bar"); + int64_t bar_id = connection.QueryCreateDirectory( + BACKUPSTORE_ROOT_DIRECTORY_ID, // containing directory + 0, // attrModTime, + dirname, // dirname, + attrStream)->GetObjectID(); + + std::auto_ptr<Configuration> config = load_config_file(); + TEST_THAT_OR(config.get(), return false); + BackupQueries query(connection, *config, false); // read-only + + TEST_EQUAL(foo_id, query.FindDirectoryObjectID("foo")); + TEST_EQUAL(foo_id, query.FindDirectoryObjectID("/foo")); + TEST_EQUAL(0, query.FindDirectoryObjectID("\\/foo")); + TEST_EQUAL(0, query.FindDirectoryObjectID("/bar")); + TEST_EQUAL(bar_id, query.FindDirectoryObjectID("\\/bar")); + connection.QueryFinished(); + + TEARDOWN(); +} + bool test_getobject_on_nonexistent_file() { SETUP_WITH_BBSTORED(); { - std::string errs; - std::auto_ptr<Configuration> config( - Configuration::LoadAndVerify - ("testfiles/bbackupd.conf", &BackupDaemonConfigVerify, errs)); + std::auto_ptr<Configuration> config = load_config_file(); + TEST_THAT_OR(config.get(), return false); std::auto_ptr<BackupProtocolCallable> connection = connect_and_login(context, 0 /* read-write */); @@ -4071,6 +4118,7 @@ int test(int argc, const char *argv[]) TEST_THAT(test_basics()); TEST_THAT(test_readdirectory_on_nonexistent_dir()); + TEST_THAT(test_bbackupquery_parser_escape_slashes()); TEST_THAT(test_getobject_on_nonexistent_file()); // TEST_THAT(test_replace_zero_byte_file_with_nonzero_byte_file()); TEST_THAT(test_backup_disappearing_directory()); |