From 77aa36fa0bff65b85b93b030f4ed31e6bace7f6a Mon Sep 17 00:00:00 2001 From: Michael O'Farrell Date: Fri, 29 May 2015 13:47:04 -0700 Subject: [PATCH] Constraint existence now check for constraints using specific operator types. This change allows QueryContext constraints to be checked for based on operator type. This makes checks for the existence of an equality operator allow enumeration. Example: if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); } --- include/osquery/tables.h | 26 ++++++++++++++++--- osquery/core/tests/tables_tests.cpp | 6 +++++ .../networking/linux/process_open_sockets.cpp | 2 +- osquery/tables/system/centos/rpm_packages.cpp | 4 +-- osquery/tables/system/darwin/certificates.mm | 2 +- .../tables/system/darwin/keychain_items.cpp | 2 +- osquery/tables/system/darwin/packages.cpp | 4 +-- osquery/tables/system/darwin/preferences.cpp | 4 +-- osquery/tables/system/darwin/processes.cpp | 2 +- osquery/tables/system/darwin/user_groups.mm | 3 +-- .../system/linux/process_open_files.cpp | 2 +- osquery/tables/system/linux/processes.cpp | 6 ++--- osquery/tables/system/linux/user_groups.cpp | 3 +-- osquery/tables/system/system_controls.cpp | 6 ++--- 14 files changed, 47 insertions(+), 25 deletions(-) diff --git a/include/osquery/tables.h b/include/osquery/tables.h index 908370ed..9c96640a 100644 --- a/include/osquery/tables.h +++ b/include/osquery/tables.h @@ -81,7 +81,7 @@ typedef std::map > TableData; * If the query contains a join or where clause with a constraint operator and * expression the table generator may limit the data appropriately. */ -enum ConstraintOperator { +enum ConstraintOperator : unsigned char { EQUALS = 2, GREATER_THAN = 4, LESS_THAN_OR_EQUALS = 8, @@ -89,6 +89,11 @@ enum ConstraintOperator { GREATER_THAN_OR_EQUALS = 32 }; +/// Type for flags for what constraint operators are admissable. +typedef unsigned char ConstraintOperatorFlag; +/// Flag for any operator type. +#define ANY_OP 0xFFU + /** * @brief A Constraint is an operator and expression. * @@ -150,15 +155,28 @@ struct ConstraintList { } /** - * @brief Check and return if there are any constraints on this column. + * @brief Check and return if there are constraints on this column. * * A ConstraintList is used in a ConstraintMap with a column name as the * map index. Tables that act on optional constraints should check if any - * constraint was provided. + * constraint was provided. The ops parameter serves to specify which + * operators we want to check existence for. * + * @param ops (Optional: default ANY_OP) The operators types to look for. * @return true if any constraint exists. */ - bool exists() const { return (constraints_.size() > 0); } + bool exists(const ConstraintOperatorFlag ops = ANY_OP) const { + if (ops == ANY_OP) { + return (constraints_.size() > 0); + } else { + for (const struct Constraint &c : constraints_) { + if (c.op & ops) { + return true; + } + } + return false; + } + } /** * @brief Check if a constraint exist AND matches the type expression. diff --git a/osquery/core/tests/tables_tests.cpp b/osquery/core/tests/tables_tests.cpp index bdd9b3ff..524dbc2c 100644 --- a/osquery/core/tests/tables_tests.cpp +++ b/osquery/core/tests/tables_tests.cpp @@ -51,13 +51,19 @@ TEST_F(TablesTests, test_constraint_matching) { struct ConstraintList cl; // An empty constraint list has expectations. EXPECT_FALSE(cl.exists()); + EXPECT_FALSE(cl.exists(GREATER_THAN)); EXPECT_TRUE(cl.notExistsOrMatches("some")); auto constraint = Constraint(EQUALS); constraint.expr = "some"; cl.add(constraint); + // Test existence checks based on flags. EXPECT_TRUE(cl.exists()); + EXPECT_TRUE(cl.exists(EQUALS)); + EXPECT_TRUE(cl.exists(EQUALS | LESS_THAN)); + EXPECT_FALSE(cl.exists(LESS_THAN)); + EXPECT_TRUE(cl.notExistsOrMatches("some")); EXPECT_TRUE(cl.matches("some")); EXPECT_FALSE(cl.notExistsOrMatches("not_some")); diff --git a/osquery/tables/networking/linux/process_open_sockets.cpp b/osquery/tables/networking/linux/process_open_sockets.cpp index edaef7db..39e39f06 100644 --- a/osquery/tables/networking/linux/process_open_sockets.cpp +++ b/osquery/tables/networking/linux/process_open_sockets.cpp @@ -127,7 +127,7 @@ QueryData genOpenSockets(QueryContext &context) { // If a pid is given then set that as the only item in processes. std::set pids; - if (context.constraints["pid"].exists()) { + if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); diff --git a/osquery/tables/system/centos/rpm_packages.cpp b/osquery/tables/system/centos/rpm_packages.cpp index 3d8f1c3c..9590a517 100644 --- a/osquery/tables/system/centos/rpm_packages.cpp +++ b/osquery/tables/system/centos/rpm_packages.cpp @@ -76,7 +76,7 @@ QueryData genRpmPackages(QueryContext& context) { rpmts ts = rpmtsCreate(); rpmdbMatchIterator matches; - if (context.constraints["name"].exists()) { + if (context.constraints["name"].exists(EQUALS)) { auto name = (*context.constraints["name"].getAll(EQUALS).begin()); matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size()); } else { @@ -116,7 +116,7 @@ QueryData genRpmPackageFiles(QueryContext& context) { rpmts ts = rpmtsCreate(); rpmdbMatchIterator matches; - if (context.constraints["package"].exists()) { + if (context.constraints["package"].exists(EQUALS)) { auto name = (*context.constraints["package"].getAll(EQUALS).begin()); matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size()); } else { diff --git a/osquery/tables/system/darwin/certificates.mm b/osquery/tables/system/darwin/certificates.mm index b2365b51..5f1defc3 100644 --- a/osquery/tables/system/darwin/certificates.mm +++ b/osquery/tables/system/darwin/certificates.mm @@ -63,7 +63,7 @@ QueryData genCerts(QueryContext &context) { // Allow the caller to set an explicit certificate (keychain) search path. std::set keychain_paths; - if (context.constraints["path"].exists()) { + if (context.constraints["path"].exists(EQUALS)) { keychain_paths = context.constraints["path"].getAll(EQUALS); } else { for (const auto& path : kSystemKeychainPaths) { diff --git a/osquery/tables/system/darwin/keychain_items.cpp b/osquery/tables/system/darwin/keychain_items.cpp index d237965f..ee72adc8 100644 --- a/osquery/tables/system/darwin/keychain_items.cpp +++ b/osquery/tables/system/darwin/keychain_items.cpp @@ -88,7 +88,7 @@ QueryData genKeychainItems(QueryContext& context) { // Allow the caller to set an explicit certificate (keychain) search path. std::set keychain_paths; - if (context.constraints["path"].exists()) { + if (context.constraints["path"].exists(EQUALS)) { keychain_paths = context.constraints["path"].getAll(EQUALS); } else { // Otherwise limit ONLY to system keychains. diff --git a/osquery/tables/system/darwin/packages.cpp b/osquery/tables/system/darwin/packages.cpp index 4703fa99..e9893a90 100644 --- a/osquery/tables/system/darwin/packages.cpp +++ b/osquery/tables/system/darwin/packages.cpp @@ -238,7 +238,7 @@ void genPackageBOM(const std::string& path, QueryData& results) { QueryData genPackageBOM(QueryContext& context) { QueryData results; - if (context.constraints["path"].exists()) { + if (context.constraints["path"].exists(EQUALS)) { // If an explicit path was given, generate and return. auto paths = context.constraints["path"].getAll(EQUALS); for (const auto& path : paths) { @@ -268,7 +268,7 @@ void genPackageReceipt(const std::string& path, QueryData& results) { QueryData genPackageReceipts(QueryContext& context) { QueryData results; - if (context.constraints["path"].exists()) { + if (context.constraints["path"].exists(EQUALS)) { // If an explicit path was given, generate and return. auto paths = context.constraints["path"].getAll(EQUALS); for (const auto& path : paths) { diff --git a/osquery/tables/system/darwin/preferences.cpp b/osquery/tables/system/darwin/preferences.cpp index ea1b97c5..5715722d 100644 --- a/osquery/tables/system/darwin/preferences.cpp +++ b/osquery/tables/system/darwin/preferences.cpp @@ -158,7 +158,7 @@ void genOSXDomainPrefs(const CFStringRef& domain, QueryData& results) { void genOSXDefaultPreferences(QueryContext& context, QueryData& results) { CFArrayRef app_map; - if (context.constraints["domain"].exists()) { + if (context.constraints["domain"].exists(EQUALS)) { // If a specific domain is requested, speed up the set of type conversions. auto domains = context.constraints["domain"].getAll(EQUALS); app_map = (CFArrayRef)CFArrayCreateMutable( @@ -243,7 +243,7 @@ void genOSXPlistPreferences(const std::string& path, QueryData& results) { QueryData genOSXPreferences(QueryContext& context) { QueryData results; - if (context.constraints["path"].exists()) { + if (context.constraints["path"].exists(EQUALS)) { // Read preferences from a plist at path. auto paths = context.constraints["path"].getAll(EQUALS); for (const auto& path : paths) { diff --git a/osquery/tables/system/darwin/processes.cpp b/osquery/tables/system/darwin/processes.cpp index ac7c452d..cb8e270b 100644 --- a/osquery/tables/system/darwin/processes.cpp +++ b/osquery/tables/system/darwin/processes.cpp @@ -34,7 +34,7 @@ namespace tables { std::set getProcList(const QueryContext &context) { std::set pidlist; if (context.constraints.count("pid") > 0 && - context.constraints.at("pid").exists()) { + context.constraints.at("pid").exists(EQUALS)) { pidlist = context.constraints.at("pid").getAll(EQUALS); } diff --git a/osquery/tables/system/darwin/user_groups.mm b/osquery/tables/system/darwin/user_groups.mm index 559c2e5c..726c2d0d 100644 --- a/osquery/tables/system/darwin/user_groups.mm +++ b/osquery/tables/system/darwin/user_groups.mm @@ -20,8 +20,7 @@ QueryData genUserGroups(QueryContext &context) { QueryData results; struct passwd *pwd = nullptr; - // TODO(1160): Add exists uid EQUALS constraint - if (context.constraints["uid"].exists()) { + if (context.constraints["uid"].exists(EQUALS)) { std::set uids = context.constraints["uid"].getAll(EQUALS); for (const auto &uid : uids) { pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10)); diff --git a/osquery/tables/system/linux/process_open_files.cpp b/osquery/tables/system/linux/process_open_files.cpp index 29e593df..8fd73801 100644 --- a/osquery/tables/system/linux/process_open_files.cpp +++ b/osquery/tables/system/linux/process_open_files.cpp @@ -41,7 +41,7 @@ QueryData genOpenFiles(QueryContext& context) { QueryData results; std::set pids; - if (context.constraints["pid"].exists()) { + if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); diff --git a/osquery/tables/system/linux/processes.cpp b/osquery/tables/system/linux/processes.cpp index be2179ae..7d309952 100644 --- a/osquery/tables/system/linux/processes.cpp +++ b/osquery/tables/system/linux/processes.cpp @@ -225,7 +225,7 @@ QueryData genProcesses(QueryContext& context) { QueryData results; std::set pids; - if (context.constraints["pid"].exists()) { + if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); @@ -245,7 +245,7 @@ QueryData genProcessEnvs(QueryContext& context) { QueryData results; std::set pids; - if (context.constraints["pid"].exists()) { + if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); @@ -262,7 +262,7 @@ QueryData genProcessMemoryMap(QueryContext& context) { QueryData results; std::set pids; - if (context.constraints["pid"].exists()) { + if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); diff --git a/osquery/tables/system/linux/user_groups.cpp b/osquery/tables/system/linux/user_groups.cpp index 773bd604..da8be007 100644 --- a/osquery/tables/system/linux/user_groups.cpp +++ b/osquery/tables/system/linux/user_groups.cpp @@ -19,8 +19,7 @@ QueryData genUserGroups(QueryContext &context) { QueryData results; struct passwd *pwd = nullptr; - // TODO(1160): Add exists uid EQUALS constraint - if (context.constraints["uid"].exists()) { + if (context.constraints["uid"].exists(EQUALS)) { std::set uids = context.constraints["uid"].getAll(EQUALS); for (const auto &uid : uids) { pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10)); diff --git a/osquery/tables/system/system_controls.cpp b/osquery/tables/system/system_controls.cpp index 4646a3b9..c91d0ca3 100644 --- a/osquery/tables/system/system_controls.cpp +++ b/osquery/tables/system/system_controls.cpp @@ -100,19 +100,19 @@ QueryData genSystemControls(QueryContext& context) { } // Iterate through the sysctl-defined macro of control types. - if (context.constraints["name"].exists()) { + if (context.constraints["name"].exists(EQUALS)) { // Request MIB information by the description (name). auto names = context.constraints["name"].getAll(EQUALS); for (const auto& name : names) { genControlInfoFromName(name, results, config); } - } else if (context.constraints["oid"].exists()) { + } else if (context.constraints["oid"].exists(EQUALS)) { // Request MIB by OID as a string, parse into set of INTs. auto oids = context.constraints["oid"].getAll(EQUALS); for (const auto& oid_string : oids) { genControlInfoFromOIDString(oid_string, results, config); } - } else if (context.constraints["subsystem"].exists()) { + } else if (context.constraints["subsystem"].exists(EQUALS)) { // Limit the MIB search to a subsystem name (first find the INT). auto subsystems = context.constraints["subsystem"].getAll(EQUALS); for (const auto& subsystem : subsystems) {