From 2fb0ab110a712f1a4e85bc6eea168afe84ff8460 Mon Sep 17 00:00:00 2001 From: iko1 Date: Sat, 8 Jan 2022 18:18:31 +0100 Subject: [PATCH 1/5] initial commit --- osquery/tables/system/posix/sudoers.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osquery/tables/system/posix/sudoers.cpp b/osquery/tables/system/posix/sudoers.cpp index 20bfa46a294..59bbabaf37a 100644 --- a/osquery/tables/system/posix/sudoers.cpp +++ b/osquery/tables/system/posix/sudoers.cpp @@ -43,6 +43,7 @@ void genSudoersFile(const std::string& filename, return; } + bool isLongLine = false; std::string contents; if (!forensicReadFile(filename, contents).ok()) { TLOG << "couldn't read sudoers file: " << filename; @@ -61,6 +62,15 @@ void genSudoersFile(const std::string& filename, continue; } + // if last line contains a backslash as the last character, + // treat current line as part of long line. + if (isLongLine) { + isLongLine = (line.at(line.size() - 1) == '\\'); + results.back()["rule_details"].pop_back(); + results.back()["rule_details"].append(line); + continue; + } + // Find the rule header auto header_len = line.find_first_of(kSudoWhitespaceChars); auto header = line.substr(0, header_len); @@ -87,6 +97,11 @@ void genSudoersFile(const std::string& filename, continue; } + // Check if a blackslash is the last character on this line. + if (!is_include && !is_includedir && line.at(line.size() - 1) == '\\') { + isLongLine = true; + } + Row r; r["header"] = header; From ce6d4842062ff567911a92912c704eae562d612a Mon Sep 17 00:00:00 2001 From: iko1 Date: Sat, 8 Jan 2022 19:44:45 +0100 Subject: [PATCH 2/5] improve backslash deletion from previous row --- osquery/tables/system/posix/sudoers.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osquery/tables/system/posix/sudoers.cpp b/osquery/tables/system/posix/sudoers.cpp index 59bbabaf37a..fd9d1c50d27 100644 --- a/osquery/tables/system/posix/sudoers.cpp +++ b/osquery/tables/system/posix/sudoers.cpp @@ -63,10 +63,15 @@ void genSudoersFile(const std::string& filename, } // if last line contains a backslash as the last character, - // treat current line as part of long line. + // treat current line as part of previous line and + // append it to appropriate column. if (isLongLine) { isLongLine = (line.at(line.size() - 1) == '\\'); - results.back()["rule_details"].pop_back(); + if (results.back()["rule_details"].empty()) { + results.back()["header"].pop_back(); + } else { + results.back()["rule_details"].pop_back(); + } results.back()["rule_details"].append(line); continue; } From 123e3ff8a3bbe12376b25da74544bb07b4868fdd Mon Sep 17 00:00:00 2001 From: iko1 Date: Wed, 12 Jan 2022 10:12:05 +0100 Subject: [PATCH 3/5] CR comments --- osquery/tables/system/posix/sudoers.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osquery/tables/system/posix/sudoers.cpp b/osquery/tables/system/posix/sudoers.cpp index fd9d1c50d27..69d39b5a781 100644 --- a/osquery/tables/system/posix/sudoers.cpp +++ b/osquery/tables/system/posix/sudoers.cpp @@ -43,7 +43,7 @@ void genSudoersFile(const std::string& filename, return; } - bool isLongLine = false; + bool is_long_line = false; std::string contents; if (!forensicReadFile(filename, contents).ok()) { TLOG << "couldn't read sudoers file: " << filename; @@ -65,8 +65,8 @@ void genSudoersFile(const std::string& filename, // if last line contains a backslash as the last character, // treat current line as part of previous line and // append it to appropriate column. - if (isLongLine) { - isLongLine = (line.at(line.size() - 1) == '\\'); + if (is_long_line) { + is_long_line = (line.back() == '\\'); if (results.back()["rule_details"].empty()) { results.back()["header"].pop_back(); } else { @@ -103,8 +103,8 @@ void genSudoersFile(const std::string& filename, } // Check if a blackslash is the last character on this line. - if (!is_include && !is_includedir && line.at(line.size() - 1) == '\\') { - isLongLine = true; + if (!is_include && !is_includedir && line.back() == '\\') { + is_long_line = true; } Row r; From 355f409940a09dddf31c320e69c0191a58707a1f Mon Sep 17 00:00:00 2001 From: iko1 Date: Wed, 12 Jan 2022 10:30:43 +0100 Subject: [PATCH 4/5] CR comment --- osquery/tables/system/posix/sudoers.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osquery/tables/system/posix/sudoers.cpp b/osquery/tables/system/posix/sudoers.cpp index 69d39b5a781..0a6d71de788 100644 --- a/osquery/tables/system/posix/sudoers.cpp +++ b/osquery/tables/system/posix/sudoers.cpp @@ -67,12 +67,13 @@ void genSudoersFile(const std::string& filename, // append it to appropriate column. if (is_long_line) { is_long_line = (line.back() == '\\'); - if (results.back()["rule_details"].empty()) { - results.back()["header"].pop_back(); + auto& last_line = results.back(); + if (last_line["rule_details"].empty()) { + last_line["header"].pop_back(); } else { - results.back()["rule_details"].pop_back(); + last_line["rule_details"].pop_back(); } - results.back()["rule_details"].append(line); + last_line["rule_details"].append(line); continue; } From 2155516eed1baa27395ba2555f0412b91d441776 Mon Sep 17 00:00:00 2001 From: iko1 Date: Fri, 28 Jan 2022 22:45:55 +0100 Subject: [PATCH 5/5] add unit test --- .../system/tests/posix/sudoers_tests.cpp | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/osquery/tables/system/tests/posix/sudoers_tests.cpp b/osquery/tables/system/tests/posix/sudoers_tests.cpp index d85f83d2240..3546df5beb6 100644 --- a/osquery/tables/system/tests/posix/sudoers_tests.cpp +++ b/osquery/tables/system/tests/posix/sudoers_tests.cpp @@ -167,5 +167,58 @@ TEST_F(SudoersTests, include_dir) { EXPECT_EQ(results[3].at("rule_details"), "env_keep += \"AT\""); } +TEST_F(SudoersTests, long_line) { + auto directory = + real_temp_path() / fs::unique_path("osquery.sudoers_tests.%%%%-%%%%"); + + ASSERT_TRUE(fs::create_directories(directory)); + + auto const path_guard = + scope_guard::create([directory]() { fs::remove_all(directory); }); + + auto sudoers_file = directory / fs::path("sudoers"); + + { + auto fout = std::ofstream(sudoers_file.native()); + fout << "# This is a comment\\\n" // comment ends with backslash + << " # with a leading space\\\n" // comment ends with backslash + << "User_Alias OTHER_USERS=foo,\\\n" // long line + << "bar,\\\n" // long line + << "baz\n" + << "User_Alias NUM_USERS=#501,#502\n" + << "User_Alias ALL_USERS = NUM_USERS,\\\n" // long line + << "OTHER_USERS\n" + << "Cmnd_Alias CMDS_1=/usr/bin/cmd1 \"a\\,b\",\\\n" // long line + << "/usr/bin/cmd2\n" + << "ALL_USERS ALL=(ALL)CMDS_1\n"; + } + + auto results = QueryData{}; + genSudoersFile(sudoers_file.string(), 1, results); + + ASSERT_EQ(results.size(), 5); + + EXPECT_EQ(results[0].at("source"), sudoers_file.string()); + EXPECT_EQ(results[0].at("header"), "User_Alias"); + EXPECT_EQ(results[0].at("rule_details"), "OTHER_USERS=foo,bar,baz"); + + EXPECT_EQ(results[1].at("source"), sudoers_file.string()); + EXPECT_EQ(results[1].at("header"), "User_Alias"); + EXPECT_EQ(results[1].at("rule_details"), "NUM_USERS=#501,#502"); + + EXPECT_EQ(results[2].at("source"), sudoers_file.string()); + EXPECT_EQ(results[2].at("header"), "User_Alias"); + EXPECT_EQ(results[2].at("rule_details"), "ALL_USERS = NUM_USERS,OTHER_USERS"); + + EXPECT_EQ(results[3].at("source"), sudoers_file.string()); + EXPECT_EQ(results[3].at("header"), "Cmnd_Alias"); + EXPECT_EQ(results[3].at("rule_details"), + "CMDS_1=/usr/bin/cmd1 \"a\\,b\",/usr/bin/cmd2"); + + EXPECT_EQ(results[4].at("source"), sudoers_file.string()); + EXPECT_EQ(results[4].at("header"), "ALL_USERS"); + EXPECT_EQ(results[4].at("rule_details"), "ALL=(ALL)CMDS_1"); +} + } // namespace tables } // namespace osquery