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);
  }
This commit is contained in:
Michael O'Farrell 2015-05-29 13:47:04 -07:00
parent ce3ac8a7e3
commit 77aa36fa0b
14 changed files with 47 additions and 25 deletions

View File

@ -81,7 +81,7 @@ typedef std::map<std::string, std::vector<std::string> > TableData;
* If the query contains a join or where clause with a constraint operator and * If the query contains a join or where clause with a constraint operator and
* expression the table generator may limit the data appropriately. * expression the table generator may limit the data appropriately.
*/ */
enum ConstraintOperator { enum ConstraintOperator : unsigned char {
EQUALS = 2, EQUALS = 2,
GREATER_THAN = 4, GREATER_THAN = 4,
LESS_THAN_OR_EQUALS = 8, LESS_THAN_OR_EQUALS = 8,
@ -89,6 +89,11 @@ enum ConstraintOperator {
GREATER_THAN_OR_EQUALS = 32 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. * @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 * 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 * 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. * @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. * @brief Check if a constraint exist AND matches the type expression.

View File

@ -51,13 +51,19 @@ TEST_F(TablesTests, test_constraint_matching) {
struct ConstraintList cl; struct ConstraintList cl;
// An empty constraint list has expectations. // An empty constraint list has expectations.
EXPECT_FALSE(cl.exists()); EXPECT_FALSE(cl.exists());
EXPECT_FALSE(cl.exists(GREATER_THAN));
EXPECT_TRUE(cl.notExistsOrMatches("some")); EXPECT_TRUE(cl.notExistsOrMatches("some"));
auto constraint = Constraint(EQUALS); auto constraint = Constraint(EQUALS);
constraint.expr = "some"; constraint.expr = "some";
cl.add(constraint); cl.add(constraint);
// Test existence checks based on flags.
EXPECT_TRUE(cl.exists()); 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.notExistsOrMatches("some"));
EXPECT_TRUE(cl.matches("some")); EXPECT_TRUE(cl.matches("some"));
EXPECT_FALSE(cl.notExistsOrMatches("not_some")); EXPECT_FALSE(cl.notExistsOrMatches("not_some"));

View File

@ -127,7 +127,7 @@ QueryData genOpenSockets(QueryContext &context) {
// If a pid is given then set that as the only item in processes. // If a pid is given then set that as the only item in processes.
std::set<std::string> pids; std::set<std::string> pids;
if (context.constraints["pid"].exists()) { if (context.constraints["pid"].exists(EQUALS)) {
pids = context.constraints["pid"].getAll(EQUALS); pids = context.constraints["pid"].getAll(EQUALS);
} else { } else {
osquery::procProcesses(pids); osquery::procProcesses(pids);

View File

@ -76,7 +76,7 @@ QueryData genRpmPackages(QueryContext& context) {
rpmts ts = rpmtsCreate(); rpmts ts = rpmtsCreate();
rpmdbMatchIterator matches; rpmdbMatchIterator matches;
if (context.constraints["name"].exists()) { if (context.constraints["name"].exists(EQUALS)) {
auto name = (*context.constraints["name"].getAll(EQUALS).begin()); auto name = (*context.constraints["name"].getAll(EQUALS).begin());
matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size()); matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size());
} else { } else {
@ -116,7 +116,7 @@ QueryData genRpmPackageFiles(QueryContext& context) {
rpmts ts = rpmtsCreate(); rpmts ts = rpmtsCreate();
rpmdbMatchIterator matches; rpmdbMatchIterator matches;
if (context.constraints["package"].exists()) { if (context.constraints["package"].exists(EQUALS)) {
auto name = (*context.constraints["package"].getAll(EQUALS).begin()); auto name = (*context.constraints["package"].getAll(EQUALS).begin());
matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size()); matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size());
} else { } else {

View File

@ -63,7 +63,7 @@ QueryData genCerts(QueryContext &context) {
// Allow the caller to set an explicit certificate (keychain) search path. // Allow the caller to set an explicit certificate (keychain) search path.
std::set<std::string> keychain_paths; std::set<std::string> keychain_paths;
if (context.constraints["path"].exists()) { if (context.constraints["path"].exists(EQUALS)) {
keychain_paths = context.constraints["path"].getAll(EQUALS); keychain_paths = context.constraints["path"].getAll(EQUALS);
} else { } else {
for (const auto& path : kSystemKeychainPaths) { for (const auto& path : kSystemKeychainPaths) {

View File

@ -88,7 +88,7 @@ QueryData genKeychainItems(QueryContext& context) {
// Allow the caller to set an explicit certificate (keychain) search path. // Allow the caller to set an explicit certificate (keychain) search path.
std::set<std::string> keychain_paths; std::set<std::string> keychain_paths;
if (context.constraints["path"].exists()) { if (context.constraints["path"].exists(EQUALS)) {
keychain_paths = context.constraints["path"].getAll(EQUALS); keychain_paths = context.constraints["path"].getAll(EQUALS);
} else { } else {
// Otherwise limit ONLY to system keychains. // Otherwise limit ONLY to system keychains.

View File

@ -238,7 +238,7 @@ void genPackageBOM(const std::string& path, QueryData& results) {
QueryData genPackageBOM(QueryContext& context) { QueryData genPackageBOM(QueryContext& context) {
QueryData results; QueryData results;
if (context.constraints["path"].exists()) { if (context.constraints["path"].exists(EQUALS)) {
// If an explicit path was given, generate and return. // If an explicit path was given, generate and return.
auto paths = context.constraints["path"].getAll(EQUALS); auto paths = context.constraints["path"].getAll(EQUALS);
for (const auto& path : paths) { for (const auto& path : paths) {
@ -268,7 +268,7 @@ void genPackageReceipt(const std::string& path, QueryData& results) {
QueryData genPackageReceipts(QueryContext& context) { QueryData genPackageReceipts(QueryContext& context) {
QueryData results; QueryData results;
if (context.constraints["path"].exists()) { if (context.constraints["path"].exists(EQUALS)) {
// If an explicit path was given, generate and return. // If an explicit path was given, generate and return.
auto paths = context.constraints["path"].getAll(EQUALS); auto paths = context.constraints["path"].getAll(EQUALS);
for (const auto& path : paths) { for (const auto& path : paths) {

View File

@ -158,7 +158,7 @@ void genOSXDomainPrefs(const CFStringRef& domain, QueryData& results) {
void genOSXDefaultPreferences(QueryContext& context, QueryData& results) { void genOSXDefaultPreferences(QueryContext& context, QueryData& results) {
CFArrayRef app_map; 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. // If a specific domain is requested, speed up the set of type conversions.
auto domains = context.constraints["domain"].getAll(EQUALS); auto domains = context.constraints["domain"].getAll(EQUALS);
app_map = (CFArrayRef)CFArrayCreateMutable( app_map = (CFArrayRef)CFArrayCreateMutable(
@ -243,7 +243,7 @@ void genOSXPlistPreferences(const std::string& path, QueryData& results) {
QueryData genOSXPreferences(QueryContext& context) { QueryData genOSXPreferences(QueryContext& context) {
QueryData results; QueryData results;
if (context.constraints["path"].exists()) { if (context.constraints["path"].exists(EQUALS)) {
// Read preferences from a plist at path. // Read preferences from a plist at path.
auto paths = context.constraints["path"].getAll(EQUALS); auto paths = context.constraints["path"].getAll(EQUALS);
for (const auto& path : paths) { for (const auto& path : paths) {

View File

@ -34,7 +34,7 @@ namespace tables {
std::set<int> getProcList(const QueryContext &context) { std::set<int> getProcList(const QueryContext &context) {
std::set<int> pidlist; std::set<int> pidlist;
if (context.constraints.count("pid") > 0 && if (context.constraints.count("pid") > 0 &&
context.constraints.at("pid").exists()) { context.constraints.at("pid").exists(EQUALS)) {
pidlist = context.constraints.at("pid").getAll<int>(EQUALS); pidlist = context.constraints.at("pid").getAll<int>(EQUALS);
} }

View File

@ -20,8 +20,7 @@ QueryData genUserGroups(QueryContext &context) {
QueryData results; QueryData results;
struct passwd *pwd = nullptr; struct passwd *pwd = nullptr;
// TODO(1160): Add exists uid EQUALS constraint if (context.constraints["uid"].exists(EQUALS)) {
if (context.constraints["uid"].exists()) {
std::set<std::string> uids = context.constraints["uid"].getAll(EQUALS); std::set<std::string> uids = context.constraints["uid"].getAll(EQUALS);
for (const auto &uid : uids) { for (const auto &uid : uids) {
pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10)); pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10));

View File

@ -41,7 +41,7 @@ QueryData genOpenFiles(QueryContext& context) {
QueryData results; QueryData results;
std::set<std::string> pids; std::set<std::string> pids;
if (context.constraints["pid"].exists()) { if (context.constraints["pid"].exists(EQUALS)) {
pids = context.constraints["pid"].getAll(EQUALS); pids = context.constraints["pid"].getAll(EQUALS);
} else { } else {
osquery::procProcesses(pids); osquery::procProcesses(pids);

View File

@ -225,7 +225,7 @@ QueryData genProcesses(QueryContext& context) {
QueryData results; QueryData results;
std::set<std::string> pids; std::set<std::string> pids;
if (context.constraints["pid"].exists()) { if (context.constraints["pid"].exists(EQUALS)) {
pids = context.constraints["pid"].getAll(EQUALS); pids = context.constraints["pid"].getAll(EQUALS);
} else { } else {
osquery::procProcesses(pids); osquery::procProcesses(pids);
@ -245,7 +245,7 @@ QueryData genProcessEnvs(QueryContext& context) {
QueryData results; QueryData results;
std::set<std::string> pids; std::set<std::string> pids;
if (context.constraints["pid"].exists()) { if (context.constraints["pid"].exists(EQUALS)) {
pids = context.constraints["pid"].getAll(EQUALS); pids = context.constraints["pid"].getAll(EQUALS);
} else { } else {
osquery::procProcesses(pids); osquery::procProcesses(pids);
@ -262,7 +262,7 @@ QueryData genProcessMemoryMap(QueryContext& context) {
QueryData results; QueryData results;
std::set<std::string> pids; std::set<std::string> pids;
if (context.constraints["pid"].exists()) { if (context.constraints["pid"].exists(EQUALS)) {
pids = context.constraints["pid"].getAll(EQUALS); pids = context.constraints["pid"].getAll(EQUALS);
} else { } else {
osquery::procProcesses(pids); osquery::procProcesses(pids);

View File

@ -19,8 +19,7 @@ QueryData genUserGroups(QueryContext &context) {
QueryData results; QueryData results;
struct passwd *pwd = nullptr; struct passwd *pwd = nullptr;
// TODO(1160): Add exists uid EQUALS constraint if (context.constraints["uid"].exists(EQUALS)) {
if (context.constraints["uid"].exists()) {
std::set<std::string> uids = context.constraints["uid"].getAll(EQUALS); std::set<std::string> uids = context.constraints["uid"].getAll(EQUALS);
for (const auto &uid : uids) { for (const auto &uid : uids) {
pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10)); pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10));

View File

@ -100,19 +100,19 @@ QueryData genSystemControls(QueryContext& context) {
} }
// Iterate through the sysctl-defined macro of control types. // 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). // Request MIB information by the description (name).
auto names = context.constraints["name"].getAll(EQUALS); auto names = context.constraints["name"].getAll(EQUALS);
for (const auto& name : names) { for (const auto& name : names) {
genControlInfoFromName(name, results, config); 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. // Request MIB by OID as a string, parse into set of INTs.
auto oids = context.constraints["oid"].getAll(EQUALS); auto oids = context.constraints["oid"].getAll(EQUALS);
for (const auto& oid_string : oids) { for (const auto& oid_string : oids) {
genControlInfoFromOIDString(oid_string, results, config); 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). // Limit the MIB search to a subsystem name (first find the INT).
auto subsystems = context.constraints["subsystem"].getAll(EQUALS); auto subsystems = context.constraints["subsystem"].getAll(EQUALS);
for (const auto& subsystem : subsystems) { for (const auto& subsystem : subsystems) {