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
* 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.

View File

@ -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"));

View File

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

View File

@ -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 {

View File

@ -63,7 +63,7 @@ QueryData genCerts(QueryContext &context) {
// Allow the caller to set an explicit certificate (keychain) search path.
std::set<std::string> 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) {

View File

@ -88,7 +88,7 @@ QueryData genKeychainItems(QueryContext& context) {
// Allow the caller to set an explicit certificate (keychain) search path.
std::set<std::string> 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.

View File

@ -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) {

View File

@ -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) {

View File

@ -34,7 +34,7 @@ namespace tables {
std::set<int> getProcList(const QueryContext &context) {
std::set<int> pidlist;
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);
}

View File

@ -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<std::string> uids = context.constraints["uid"].getAll(EQUALS);
for (const auto &uid : uids) {
pwd = getpwuid(std::strtol(uid.c_str(), NULL, 10));

View File

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

View File

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

View File

@ -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<std::string> uids = context.constraints["uid"].getAll(EQUALS);
for (const auto &uid : uids) {
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.
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) {