Esempio n. 1
0
std::string generateRow(const Row& r,
                        const std::map<std::string, size_t>& lengths,
                        const std::vector<std::string>& order) {
  std::string out;
  for (const auto& column : order) {
    size_t size = 0;

    // Print a terminator for the previous value or lhs, followed by spaces.
    out += kToken + ' ';
    if (r.count(column) == 0 || lengths.count(column) == 0) {
      size = column.size() - utf8StringSize(FLAGS_nullvalue);
      out += FLAGS_nullvalue;
    } else {
      int buffer_size =
          static_cast<int>(lengths.at(column) - utf8StringSize(r.at(column)));
      if (buffer_size >= 0) {
        size = static_cast<size_t>(buffer_size);
        out += r.at(column);
      }
    }
    out += std::string(size + 1, ' ');
  }

  if (out.size() > 0) {
    // Only append if a row was added.
    out += kToken + "\n";
  }

  return out;
}
Esempio n. 2
0
std::string generateRow(const Row& r,
                        const std::map<std::string, int>& lengths,
                        const std::vector<std::string>& order) {
  std::ostringstream row;

  row << "|";
  for (const auto& each : order) {
    row << " ";
    try {
      row << r.at(each);
      for (int i = 0; i < (lengths.at(each) - r.at(each).size() + 1); ++i) {
        row << " ";
      }
    } catch (const std::out_of_range& e) {
      LOG(ERROR) << "printing the faulty row";
      for (const auto& foo : r) {
        LOG(ERROR) << foo.first << " => " << foo.second;
      }
      LOG(ERROR) << "Error retreiving the \"" << each
                 << "\" key in generateRow:  " << e.what();
    }
    row << "|";
  }
  row << "\n";

  return row.str();
}
Esempio n. 3
0
Status ProcessEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
  // Check and set the valid state change.
  // If this is an unacceptable change reset the state and clear row data.
  if (ec->fields.count("success") && ec->fields.at("success") == "no") {
    return Status(0, "OK");
  }

  if (!validAuditState(ec->type, state_).ok()) {
    state_ = STATE_SYSCALL;
    Row().swap(row_);
    return Status(0, "OK");
  }

  // Fill in row fields based on the event state.
  updateAuditRow(ec, row_);

  // Only add the event if finished (aka a PATH event was emitted).
  if (state_ == STATE_SYSCALL) {
    // If the EXECVE state was not used, decode the cmdline value.
    if (row_.at("cmdline_size").size() == 0) {
      // This allows at most 1 decode call per potentially-encoded item.
      row_["cmdline"] = decodeAuditValue(row_.at("cmdline"));
      row_["cmdline_size"] = "1";
    }

    add(row_, getUnixTime());
    Row().swap(row_);
  }

  return Status(0, "OK");
}
Esempio n. 4
0
inline void updateAuditRow(const AuditEventContextRef& ec, Row& r) {
  const auto& fields = ec->fields;
  if (ec->type == AUDIT_SYSCALL) {
    r["pid"] = (fields.count("pid")) ? fields.at("pid") : "0";
    r["parent"] = fields.count("ppid") ? fields.at("ppid") : "0";
    r["uid"] = fields.count("uid") ? fields.at("uid") : "0";
    r["euid"] = fields.count("euid") ? fields.at("euid") : "0";
    r["gid"] = fields.count("gid") ? fields.at("gid") : "0";
    r["egid"] = fields.count("egid") ? fields.at("euid") : "0";
    r["path"] = (fields.count("exe")) ? decodeAuditValue(fields.at("exe")) : "";

    // This should get overwritten during the EXECVE state.
    r["cmdline"] = (fields.count("comm")) ? fields.at("comm") : "";
    // Do not record a cmdline size. If the final state is reached and no 'argc'
    // has been filled in then the EXECVE state was not used.
    r["cmdline_size"] = "";

    r["overflows"] = "";
    r["env_size"] = "0";
    r["env_count"] = "0";
    r["env"] = "";
  }

  if (ec->type == AUDIT_EXECVE) {
    // Reset the temporary storage from the SYSCALL state.
    r["cmdline"] = "";
    for (const auto& arg : fields) {
      if (arg.first == "argc") {
        continue;
      }

      // Amalgamate all the "arg*" fields.
      if (r.at("cmdline").size() > 0) {
        r["cmdline"] += " ";
      }
      r["cmdline"] += decodeAuditValue(arg.second);
    }

    // There may be a better way to calculate actual size from audit.
    // Then an overflow could be calculated/determined based on actual/expected.
    r["cmdline_size"] = std::to_string(r.at("cmdline").size());
  }

  if (ec->type == AUDIT_PATH) {
    r["mode"] = (fields.count("mode")) ? fields.at("mode") : "";
    r["owner_uid"] = fields.count("ouid") ? fields.at("ouid") : "0";
    r["owner_gid"] = fields.count("ogid") ? fields.at("ogid") : "0";

    auto qd = SQL::selectAllFrom("file", "path", EQUALS, r.at("path"));
    if (qd.size() == 1) {
      r["ctime"] = qd.front().at("ctime");
      r["atime"] = qd.front().at("atime");
      r["mtime"] = qd.front().at("mtime");
      r["btime"] = "0";
    }

    // Uptime is helpful for execution-based events.
    r["uptime"] = std::to_string(tables::getUptime());
  }
}
Esempio n. 5
0
Status YARAEventSubscriber::Callback(const FileEventContextRef& ec,
                                     const void* user_data) {
  if (user_data == nullptr) {
    return Status(1, "No YARA category string provided");
  }

  if (ec->action != "UPDATED" && ec->action != "CREATED") {
    return Status(1, "Invalid action");
  }

  Row r;
  r["action"] = ec->action;
  r["target_path"] = ec->path;
  r["category"] = *(std::string*)user_data;

  // Only FSEvents transactions updates (inotify is a no-op).
  r["transaction_id"] = INTEGER(ec->transaction_id);

  // These are default values, to be updated in YARACallback.
  r["count"] = INTEGER(0);
  r["matches"] = std::string("");
  r["strings"] = std::string("");
  r["tags"] = std::string("");

  ConfigDataInstance config;
  const auto& parser = config.getParser("yara");
  if (parser == nullptr)
    return Status(1, "ConfigParser unknown.");
  const auto& yaraParser = std::static_pointer_cast<YARAConfigParserPlugin>(parser);
  auto rules = yaraParser->rules();

  // Use the category as a lookup into the yara file_paths. The value will be
  // a list of signature groups to scan with.
  auto category = r.at("category");
  const auto& yara_config = config.getParsedData("yara");
  const auto& yara_paths = yara_config.get_child("file_paths");
  const auto& sig_groups = yara_paths.find(category);
  for (const auto& rule : sig_groups->second) {
    const std::string group = rule.second.data();
    int result = yr_rules_scan_file(rules[group],
                                    ec->path.c_str(),
                                    SCAN_FLAGS_FAST_MODE,
                                    YARACallback,
                                    (void*)&r,
                                    0);

    if (result != ERROR_SUCCESS) {
      return Status(1, "YARA error: " + std::to_string(result));
    }
  }

  if (ec->action != "" && r.at("matches").size() > 0) {
    add(r, ec->time);
  }

  return Status(0, "OK");
}
Esempio n. 6
0
void genBrowserPlugin(const std::string& uid,
                      const std::string& path,
                      QueryData& results,
                      bool is_disabled = false) {
  Row r;
  pt::ptree tree;

  r["uid"] = uid;
  auto info_path = path + "/Contents/Info.plist";
  // Ensure that what we're processing is actually a plug-in.
  if (!pathExists(info_path)) {
    return;
  }
  if (osquery::parsePlist(info_path, tree).ok()) {
    // Plugin did not include an Info.plist, or it was invalid
    for (const auto& it : kBrowserPluginKeys) {
      r[it.second] = tree.get(it.first, "");

      // Convert bool-types to an integer.
      jsonBoolAsInt(r[it.second]);
    }
  }

  if (r.count("native") == 0 || r.at("native").size() == 0) {
    // The default case for native execution is false.
    r["native"] = "0";
  }
  r["path"] = path;
  r["disabled"] = (is_disabled) ? "1" : "0";
  results.push_back(std::move(r));
}
Esempio n. 7
0
void EventSubscriberPlugin::expireCheck(bool cleanup) {
  auto data_key = "data." + dbNamespace();
  auto eid_key = "eid." + dbNamespace();
  // Min key will be the last surviving key.
  size_t min_key = 0;

  {
    auto limit = getEventsMax();
    std::vector<std::string> keys;
    scanDatabaseKeys(kEvents, keys, data_key);
    if (keys.size() <= limit) {
      return;
    }

    // There is an overflow of events buffered for this subscriber.
    LOG(WARNING) << "Expiring events for subscriber: " << getName()
                 << " (limit " << limit << ")";
    VLOG(1) << "Subscriber events " << getName() << " exceeded limit " << limit
            << " by: " << keys.size() - limit;
    // Inspect the N-FLAGS_events_max -th event's value and expire before the
    // time within the content.
    std::string last_key;
    getDatabaseValue(kEvents, eid_key, last_key);
    // The EID is the next-index.
    // EID - events_max is the most last-recent event to keep.
    min_key = boost::lexical_cast<size_t>(last_key) - getEventsMax();

    if (cleanup) {
      // Scan each of the keys in keys, if their ID portion is < min_key.
      // Nix them, this requires lots of conversions, use with care.
      for (const auto& key : keys) {
        if (std::stoul(key.substr(key.rfind('.') + 1)) < min_key) {
          deleteDatabaseValue(kEvents, key);
        }
      }
    }
  }

  // Convert the key index into a time using the content.
  // The last-recent event is fetched and the corresponding time is used as
  // the expiration time for the subscriber.
  std::string content;
  getDatabaseValue(kEvents, data_key + "." + std::to_string(min_key), content);

  // Decode the value into a row structure to extract the time.
  Row r;
  if (!deserializeRowJSON(content, r) || r.count("time") == 0) {
    return;
  }

  // The last time will become the implicit expiration time.
  size_t last_time = boost::lexical_cast<size_t>(r.at("time"));
  if (last_time > 0) {
    expire_time_ = last_time;
  }

  // Finally, attempt an index query to trigger expirations.
  // In this case the result set is not used.
  getIndexes(expire_time_, 0);
}
Esempio n. 8
0
void genBrowserPlugin(const std::string& uid,
                      const std::string& path,
                      QueryData& results) {
  Row r;
  pt::ptree tree;

  r["uid"] = uid;
  if (osquery::parsePlist(path + "/Contents/Info.plist", tree).ok()) {
    // Plugin did not include an Info.plist, or it was invalid
    for (const auto& it : kBrowserPluginKeys) {
      r[it.second] = tree.get(it.first, "");

      // Convert bool-types to an integer.
      jsonBoolAsInt(r[it.second]);
    }
  }

  if (r.count("native") == 0 || r.at("native").size() == 0) {
    // The default case for native execution is false.
    r["native"] = "0";
  }

  r["path"] = path;
  results.push_back(std::move(r));
}
Esempio n. 9
0
void genFDEStatusForBSDName(const std::string& bsd_name,
                            const std::string& uuid,
                            QueryData& results) {

  auto matching_dict =
      IOBSDNameMatching(kIOMasterPortDefault, kNilOptions, bsd_name.c_str());
  if (matching_dict == nullptr) {
    CFRelease(matching_dict);
    return;
  }

  auto service =
      IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict);
  if (!service) {
    IOObjectRelease(service);
    return;
  }

  CFMutableDictionaryRef properties;
  IORegistryEntryCreateCFProperties(
      service, &properties, kCFAllocatorDefault, kNilOptions);

  Row r;

  r["name"] = kDeviceNamePrefix + bsd_name;
  r["uuid"] = uuid;

  auto encrypted = getIOKitProperty(properties, kCoreStorageIsEncryptedKey_);
  r["encrypted"] = (encrypted.empty()) ? "0" : encrypted;
  r["type"] = (r.at("encrypted") == "1") ? kEncryptionType : std::string();

  results.push_back(r);
  CFRelease(properties);
  IOObjectRelease(service);
}
Esempio n. 10
0
void genControlInfo(const std::string& mib_path,
                    QueryData& results,
                    const std::map<std::string, std::string>& config) {
  if (isDirectory(mib_path).ok()) {
    // Iterate through the subitems and items.
    std::vector<std::string> items;
    if (listDirectoriesInDirectory(mib_path, items).ok()) {
      for (const auto& item : items) {
        genControlInfo(item, results, config);
      }
    }

    if (listFilesInDirectory(mib_path, items).ok()) {
      for (const auto& item : items) {
        genControlInfo(item, results, config);
      }
    }
    return;
  }

  // This is a file (leaf-control).
  Row r;
  r["name"] = mib_path.substr(kSystemControlPath.size());

  std::replace(r["name"].begin(), r["name"].end(), '/', '.');
  // No known way to convert name MIB to int array.
  r["subsystem"] = osquery::split(r.at("name"), ".")[0];

  if (isReadable(mib_path).ok()) {
    std::string content;
    readFile(mib_path, content);
    boost::trim(content);
    r["current_value"] = content;
  }

  if (config.count(r.at("name")) > 0) {
    r["config_value"] = config.at(r.at("name"));
  }
  r["type"] = "string";
  results.push_back(r);
}
Esempio n. 11
0
	bool SelectionOperator::next() {
		assert(isOpen);

		while (in.next()) {
			Row input = in.getOutput();
			
			if (*(input.at(index)) == constant)
				return true;
		}

		return false;
	}
Esempio n. 12
0
void Config::recordQueryPerformance(const std::string& name,
                                    size_t delay,
                                    size_t size,
                                    const Row& r0,
                                    const Row& r1) {
  // Grab a lock on the schedule structure and check the name.
  ConfigDataInstance config;
  if (config.schedule().count(name) == 0) {
    // Unknown query schedule name.
    return;
  }

  // Grab access to the non-const schedule item.
  auto& query = getInstance().data_.schedule.at(name);
  auto diff = strtol(r1.at("user_time").c_str(), nullptr, 10) -
              strtol(r0.at("user_time").c_str(), nullptr, 10);
  query.user_time += diff;
  diff = strtol(r1.at("system_time").c_str(), nullptr, 10) -
         strtol(r0.at("system_time").c_str(), nullptr, 10);
  query.system_time += diff;
  diff = strtol(r1.at("resident_size").c_str(), nullptr, 10) -
         strtol(r0.at("resident_size").c_str(), nullptr, 10);
  // Memory is stored as an average of BSS changes between query executions.
  query.memory =
      (query.memory * query.executions + diff) / (query.executions + 1);
  query.wall_time += delay;
  query.output_size += size;
  query.executions += 1;
}
Esempio n. 13
0
//add database items into this tree, be careful!
//input: the database items pointer p_d
//retval: bool; true--> add all of them ok
//              false--> something goes wrong
bool Tree:: addDatabaseItems( const Mat<double> * p_d )
{
    size_t r,c;
    TreeNode * current;
    Mat<double> result;

    r = p_d->n_rows;
    c = p_d->n_cols - 1 ;

    Row< double > tmp;
    for( size_t i = 0 ; i < r ; i ++ )
    {
        tmp = p_d->row( i );

        tmp.at( c ) = 1;    //the x sample needs to become this x=[x0 x1 x2 ... 1 ]

        current = root;

        while( (current != NULL) && ( current->isInternal() ))
        {
            result = tmp * (current->intL).pvector->at(0) ;

            if( result.at( 0 ) > 0 )
            {
                current = current->intL.left;
            }else
            {
                current = current->intL.right;
            }
        }

        if( NULL == current )
        {
            cerr <<"current is null in the addDatabaseIntems()\b";
            return false;
        }

        if( NULL == current->leafL.puivector )
        {
            current->leafL.puivector = new vector< unsigned int >;
        }

        (current->leafL).puivector->push_back( i );

    }

    return true;
}
Esempio n. 14
0
void genFDEStatusForBSDName(const std::string& bsd_name,
                            const std::string& uuid,
                            QueryData& results) {

  auto matching_dict =
      IOBSDNameMatching(kIOMasterPortDefault, kNilOptions, bsd_name.c_str());
  if (matching_dict == nullptr) {
    return;
  }

  auto service =
      IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict);
  if (!service) {
    return;
  }

  CFMutableDictionaryRef properties;
  if (IORegistryEntryCreateCFProperties(
          service, &properties, kCFAllocatorDefault, kNilOptions) !=
      KERN_SUCCESS) {
    IOObjectRelease(service);
    return;
  }

  Row r;
  r["name"] = kDeviceNamePrefix + bsd_name;
  r["uuid"] = uuid;

  auto encrypted = getIOKitProperty(properties, kCoreStorageIsEncryptedKey_);
  if (encrypted.empty()) {
    r["encrypted"] = "0";
  } else {
    r["encrypted"] = encrypted;
    id_t uid;
    uuid_string_t uuid_string = {0};
    if (genUid(uid, uuid_string).ok()) {
      r["uid"] = BIGINT(uid);
      r["user_uuid"] = TEXT(uuid_string);
    }
  }
  r["type"] = (r.at("encrypted") == "1") ? kEncryptionType : std::string();

  results.push_back(r);
  CFRelease(properties);
  IOObjectRelease(service);
}
Esempio n. 15
0
void genOSXPrefValues(const CFTypeRef& value,
                      const Row& base,
                      QueryData& results,
                      size_t depth) {
  if (value == nullptr) {
    return;
  }

  // Since we recurse when parsing Arrays/Dicts, monitor stack limits.
  if (++depth > kPreferenceDepthLimit) {
    TLOG << "The macOS preference: " << base.at("domain")
         << " exceeded subkey depth limit: " << kPreferenceDepthLimit;
    return;
  }

  // Emit a string representation for each preference type.
  Row r = base;
  if (CFGetTypeID(value) == CFNumberGetTypeID()) {
    r["value"] = stringFromCFNumber(static_cast<CFDataRef>(value));
  } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
    r["value"] = stringFromCFString(static_cast<CFStringRef>(value));
  } else if (CFGetTypeID(value) == CFDateGetTypeID()) {
    auto unix_time = CFDateGetAbsoluteTime(static_cast<CFDateRef>(value)) +
                     kCFAbsoluteTimeIntervalSince1970;
    r["value"] = boost::lexical_cast<std::string>(std::llround(unix_time));
  } else if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
    r["value"] = (CFBooleanGetValue(static_cast<CFBooleanRef>(value)) == TRUE)
                     ? "true"
                     : "false";
  } else if (CFGetTypeID(value) == CFDataGetTypeID()) {
    // Do not include data preferences.
  } else if (CFGetTypeID(value) == CFArrayGetTypeID()) {
    genOSXListPref(static_cast<CFArrayRef>(value), base, results, depth);
    return;
  } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
    // Generate a row for each hash key.
    TRowResults trow(base, results, depth);
    CFDictionaryApplyFunction(
        static_cast<CFDictionaryRef>(value), &genOSXHashPref, &trow);
    return;
  }

  results.push_back(std::move(r));
}
Esempio n. 16
0
void genExtension(const std::string& path, QueryData& results) {
  std::string json_data;
  if (!readFile(path + kManifestFile, json_data).ok()) {
    VLOG(1) << "Could not read file: " << path + kManifestFile;
    return;
  }

  // Read the extensions data into a JSON blob, then property tree.
  pt::ptree tree;
  std::stringstream json_stream;
  json_stream << json_data;
  try {
    pt::read_json(json_stream, tree);
  } catch (const pt::json_parser::json_parser_error& e) {
    VLOG(1) << "Could not parse JSON from: " << path + kManifestFile;
    return;
  }

  Row r;
  // Most of the keys are in the top-level JSON dictionary.
  for (const auto& it : kExtensionKeys) {
    try {
      r[it.second] = tree.get<std::string>(it.first);
    } catch (const pt::ptree_error& e) {
      r[it.second] = "";
    }

    // Convert JSON bool-types to an integer.
    if (r[it.second] == "true") {
      r[it.second] = INTEGER(1);
    } else if (r[it.second] == "false") {
      r[it.second] = INTEGER(0);
    }
  }

  // Set the default persistence setting to false
  if (r.at("persistent") == "") {
    r["persistent"] = INTEGER(0);
  }

  r["identifier"] = fs::path(path).parent_path().leaf().string();
  r["path"] = path;
  results.push_back(r);
}
Esempio n. 17
0
void EventSubscriberPlugin::expireCheck() {
  auto db = DBHandle::getInstance();
  auto data_key = "data." + dbNamespace();
  auto eid_key = "eid." + dbNamespace();

  std::vector<std::string> keys;
  db->ScanPrefix(kEvents, keys, data_key);
  if (keys.size() <= FLAGS_events_max) {
    return;
  }

  // There is an overflow of events buffered for this subscriber.
  LOG(WARNING) << "Expiring events for subscriber: " << getName() << " limit ("
               << FLAGS_events_max << ") exceeded: " << keys.size();
  // Inspect the N-FLAGS_events_max -th event's value and expire before the
  // time within the content.
  std::string last_key;
  db->Get(kEvents, eid_key, last_key);
  // The EID is the next-index.
  size_t max_key = boost::lexical_cast<size_t>(last_key) - FLAGS_events_max - 1;

  // Convert the key index into a time using the content.
  std::string content;
  db->Get(kEvents, data_key + "." + std::to_string(max_key), content);

  // Decode the value into a row structure to extract the time.
  Row r;
  if (!deserializeRowJSON(content, r) || r.count("time") == 0) {
    return;
  }

  // The last time will become the implicit expiration time.
  size_t last_time = boost::lexical_cast<size_t>(r.at("time"));
  if (last_time > 0) {
    expire_time_ = last_time;
  }

  // Finally, attempt an index query to trigger expirations.
  // In this case the result set is not used.
  getIndexes(expire_time_ - 1, -1);
}
Esempio n. 18
0
void Config::recordQueryPerformance(const std::string& name,
                                    size_t delay,
                                    size_t size,
                                    const Row& r0,
                                    const Row& r1) {
  // Grab a lock on the schedule structure and check the name.
  ConfigDataInstance config;
  if (config.schedule().count(name) == 0) {
    // Unknown query schedule name.
    return;
  }

  // Grab access to the non-const schedule item.
  auto& query = getInstance().data_.schedule.at(name);
  auto diff = AS_LITERAL(BIGINT_LITERAL, r1.at("user_time")) -
              AS_LITERAL(BIGINT_LITERAL, r0.at("user_time"));
  if (diff > 0) {
    query.user_time += diff;
  }

  diff = AS_LITERAL(BIGINT_LITERAL, r1.at("system_time")) -
         AS_LITERAL(BIGINT_LITERAL, r0.at("system_time"));
  if (diff > 0) {
    query.system_time += diff;
  }

  diff = AS_LITERAL(BIGINT_LITERAL, r1.at("resident_size")) -
         AS_LITERAL(BIGINT_LITERAL, r0.at("resident_size"));
  if (diff > 0) {
    // Memory is stored as an average of RSS changes between query executions.
    query.average_memory = (query.average_memory * query.executions) + diff;
    query.average_memory = (query.average_memory / (query.executions + 1));
  }

  query.wall_time += delay;
  query.output_size += size;
  query.executions += 1;
}
Esempio n. 19
0
void Config::recordQueryPerformance(const std::string& name,
                                    size_t delay,
                                    size_t size,
                                    const Row& r0,
                                    const Row& r1) {
  RecursiveLock lock(config_performance_mutex_);
  if (performance_.count(name) == 0) {
    performance_[name] = QueryPerformance();
  }

  // Grab access to the non-const schedule item.
  auto& query = performance_.at(name);
  BIGINT_LITERAL diff = 0;
  if (!r1.at("user_time").empty() && !r0.at("user_time").empty()) {
    diff = AS_LITERAL(BIGINT_LITERAL, r1.at("user_time")) -
           AS_LITERAL(BIGINT_LITERAL, r0.at("user_time"));
    if (diff > 0) {
      query.user_time += diff;
    }
  }

  if (!r1.at("system_time").empty() && !r0.at("system_time").empty()) {
    diff = AS_LITERAL(BIGINT_LITERAL, r1.at("system_time")) -
           AS_LITERAL(BIGINT_LITERAL, r0.at("system_time"));
    if (diff > 0) {
      query.system_time += diff;
    }
  }

  if (!r1.at("resident_size").empty() && !r0.at("resident_size").empty()) {
    diff = AS_LITERAL(BIGINT_LITERAL, r1.at("resident_size")) -
           AS_LITERAL(BIGINT_LITERAL, r0.at("resident_size"));
    if (diff > 0) {
      // Memory is stored as an average of RSS changes between query executions.
      query.average_memory = (query.average_memory * query.executions) + diff;
      query.average_memory = (query.average_memory / (query.executions + 1));
    }
  }

  query.wall_time += delay;
  query.output_size += size;
  query.executions += 1;
  query.last_executed = getUnixTime();

  // Clear the executing query (remove the dirty bit).
  setDatabaseValue(kPersistentSettings, kExecutingQuery, "");
}
Esempio n. 20
0
void genControlInfo(int* oid,
                    size_t oid_size,
                    QueryData& results,
                    const std::map<std::string, std::string>& config) {
  Row r;
  if (oid_size == 0) {
    return;
  }

  r["oid"] = stringFromMIB(oid, oid_size);
  // Request the description (the canonical name) for the MIB.
  char response[CTL_MAX_VALUE] = {0};
  size_t response_size = CTL_MAX_VALUE;

  int request[CTL_MAXNAME + 2] = {0, CTL_DEBUG_DESCRIPTION};
  memcpy(request + 2, oid, oid_size * sizeof(int));
  if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) {
    return;
  }

  r["name"] = std::string(response);
  if (oid[0] > 0 && oid[0] < static_cast<int>(kControlNames.size())) {
    r["subsystem"] = kControlNames[oid[0]];
  }

  // Now request structure type.
  request[1] = CTL_DEBUG_TYPE;
  if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) {
    // Cannot request MIB type (int, string, struct, etc).
    return;
  }

  size_t oid_type = 0;
  if (response_size > 0) {
    oid_type = ((size_t)response[0] & CTLTYPE);
    if (oid_type < kControlTypes.size()) {
      r["type"] = kControlTypes[((int)response[0])];
    }
  }

  // Finally request MIB value.
  if (oid_type > CTLTYPE_NODE && oid_type < CTLTYPE_OPAQUE) {
    size_t value_size = 0;
    sysctl(oid, oid_size, 0, &value_size, 0, 0);

    if (value_size > CTL_MAX_VALUE) {
      // If the value size is larger than the max value, limit.
      value_size = CTL_MAX_VALUE;
    }

    sysctl(oid, oid_size, response, &value_size, 0, 0);
    if (oid_type == CTLTYPE_INT) {
      unsigned int value;
      memcpy(&value, response, sizeof(int));
      r["current_value"] = INTEGER(value);
    } else if (oid_type == CTLTYPE_STRING) {
      r["current_value"] = std::string(response);
    } else if (oid_type == CTLTYPE_QUAD) {
      unsigned long long value;
      memcpy(&value, response, value_size);
    }
  }

  // If this MIB was set using sysctl.conf add the value.
  if (config.count(r.at("name")) > 0) {
    r["config_value"] = config.at(r["name"]);
  }

  results.push_back(r);
}
Esempio n. 21
0
QueryData genDrivers(QueryContext& context) {
  QueryData results;

  auto devInfoset = setupDevInfoSet();
  if (devInfoset == nullptr) {
    win32LogWARNING("Error getting device handle");
    return results;
  }

  std::vector<SP_DEVINFO_DATA> devices;
  auto ret = getDeviceList(devInfoset, devices);
  if (!ret.ok()) {
    win32LogWARNING(ret.getMessage(), ret.getCode());
    return results;
  }

  for (auto& device : devices) {
    char devId[MAX_DEVICE_ID_LEN] = {0};
    if (CM_Get_Device_ID(device.DevInst, devId, MAX_DEVICE_ID_LEN, 0) !=
        CR_SUCCESS) {
      win32LogWARNING("Failed to get device ID");
      return QueryData();
    }

    SP_DRVINFO_DATA drvInfo = {0};
    SP_DRVINFO_DETAIL_DATA drvInfoDetail = {0};
    ret = getDeviceDriverInfo(devInfoset, device, drvInfo, drvInfoDetail);

    Row r;
    r["device_id"] = devId;
    r["inf"] = drvInfoDetail.InfFileName;
    r["provider"] = drvInfo.ProviderName;
    r["manufacturer"] = drvInfo.MfgName;
    r["date"] = std::to_string(osquery::filetimeToUnixtime(drvInfo.DriverDate));
    r["description"] = drvInfo.Description;
    ULARGE_INTEGER version;
    version.QuadPart = drvInfo.DriverVersion;
    r["version"] = std::to_string(HIWORD(version.HighPart)) + "." +
                   std::to_string(HIWORD(version.LowPart)) + "." +
                   std::to_string(LOWORD(version.HighPart)) + "." +
                   std::to_string(LOWORD(version.LowPart));

    for (const auto& elem : kAdditionalDeviceProps) {
      std::string val;
      ret = getDeviceProperty(devInfoset, device, elem.second, val);
      r[elem.first] = std::move(val);
    }

    if (r.count("driver_key") > 0) {
      if (!r.at("driver_key").empty()) {
        r["driver_key"].insert(0, kDriverKeyPath);
      }
    }
    if (r.count("service") > 0) {
      if (!r.at("service").empty()) {
        r["service_key"] = kServiceKeyPath + r["service"];
        r["image"] = getDriverImagePath(r["service_key"]);
      }
    }

    results.push_back(r);
  }

  return results;
}
Esempio n. 22
0
void genControlInfo(int* oid,
                    size_t oid_size,
                    QueryData& results,
                    const std::map<std::string, std::string>& config) {
  Row r;
  if (oid_size == 0) {
    return;
  }

  r["oid"] = stringFromMIB(oid, oid_size);
  // Request the description (the canonical name) for the MIB.
  char response[CTL_MAX_VALUE] = {0};
  size_t response_size = CTL_MAX_VALUE;

  int request[CTL_MAXNAME + 2] = {0, CTL_DEBUG_DESCRIPTION};
  memcpy(request + 2, oid, oid_size * sizeof(int));
  if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) {
    return;
  }

  r["name"] = std::string(response);
  if (oid[0] > 0 && oid[0] < static_cast<int>(kControlNames.size())) {
    r["subsystem"] = kControlNames[oid[0]];
  }

  // Now request structure type.
  response_size = CTL_MAX_VALUE;
  request[1] = CTL_DEBUG_TYPE;
  if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) {
    // Cannot request MIB type (int, string, struct, etc).
    return;
  }

  size_t oid_type = 0;
  if (response_size > 0) {
    oid_type = ((size_t)response[0] & CTLTYPE);
    if ((oid_type == 0 || oid_type == CTLTYPE_INT) && response_size > 4) {
      // For whatever reason, macOS defines fewer CTLTYPE's than BSD, and
      // sometimes uses the format character instead of (or in addition to)
      // the CTLTYPE to specify the type. Here we detect a few such cases and
      // map them to CTLTYPE's.
      // TODO: Both CTLTYPE_INT and CTLTYPE_QUAD can be specified as unsigned
      // using a similar method.
      char type_char = response[4];
      switch (type_char) {
      case 'I':
        oid_type = CTLTYPE_INT;
        break;
      case 'L':
        if (sizeof(long) == sizeof(long long)) {
          oid_type = CTLTYPE_QUAD;
        } else if (sizeof(long) == sizeof(int)) {
          oid_type = CTLTYPE_INT;
        }
        break;
      case 'S':
        oid_type = CTLTYPE_STRUCT;
        break;
      case 'Q':
        oid_type = CTLTYPE_QUAD;
        break;
        // Otherwise leave the type as it was; we have no additional knowledge
      }
    }
    if (oid_type < kControlTypes.size()) {
      r["type"] = kControlTypes[oid_type];
    }
  }

  // Finally request MIB value.
  if (oid_type > CTLTYPE_NODE && oid_type < CTLTYPE_OPAQUE) {
    size_t value_size = 0;
    sysctl(oid, oid_size, 0, &value_size, 0, 0);

    if (value_size > CTL_MAX_VALUE) {
      // If the value size is larger than the max value, limit.
      value_size = CTL_MAX_VALUE;
    }

    sysctl(oid, oid_size, response, &value_size, 0, 0);
    if (oid_type == CTLTYPE_INT) {
      unsigned int value;
      memcpy(&value, response, sizeof(int));
      r["current_value"] = INTEGER(value);
    } else if (oid_type == CTLTYPE_STRING) {
      r["current_value"] = std::string(response);
    } else if (oid_type == CTLTYPE_QUAD) {
      unsigned long long value;
      memcpy(&value, response, sizeof(unsigned long long));
      r["current_value"] = INTEGER(value);
    }
  }

  // If this MIB was set using sysctl.conf add the value.
  if (config.count(r.at("name")) > 0) {
    r["config_value"] = config.at(r["name"]);
  }

  results.push_back(r);
}
Esempio n. 23
0
void genOSXDomainPrefs(const CFStringRef& username,
                       const CFStringRef& domain,
                       bool current_host,
                       QueryData& results) {
  const auto* user = (username != nullptr)
                         ? &username
                         : (isUserAdmin()) ? &kCFPreferencesAnyUser
                                           : &kCFPreferencesCurrentUser;
  const auto* host =
      (current_host) ? &kCFPreferencesCurrentHost : &kCFPreferencesAnyHost;
  auto keys = CFPreferencesCopyKeyList(domain, *user, *host);
  if (keys == nullptr) {
    return;
  }

  auto values = CFPreferencesCopyMultiple(keys, domain, *user, *host);
  if (values == nullptr) {
    CFRelease(keys);
    return;
  }

  std::string username_string;
  if (username != nullptr) {
    username_string = stringFromCFString(username);
  }

  // Iterate over each preference domain's preference name.
  for (CFIndex j = 0; j < CFArrayGetCount(keys); ++j) {
    Row r;

    r["username"] = username_string;
    r["host"] = (current_host) ? "current" : "any";
    r["domain"] = stringFromCFString(domain);
    auto key = static_cast<CFStringRef>(CFArrayGetValueAtIndex(keys, j));
    if (CFStringGetTypeID() != CFGetTypeID(key)) {
      continue;
    }

    // Interesting results/behavior from Microsoft products.
    r["key"] = stringFromCFString(key);
    if (r.at("key").find('>') != std::string::npos ||
        r.at("key").find('<') != std::string::npos || r.at("key").size() == 0) {
      continue;
    }

    // Check if the preference key is managed by a profile.
    auto forced = CFPreferencesAppValueIsForced(key, domain);
    r["forced"] = (forced) ? '1' : '0';

    CFTypeRef value = nullptr;
    if (forced) {
      value = static_cast<CFTypeRef>(CFPreferencesCopyAppValue(key, domain));
    } else {
      // Check the key and key type (which may be any CF type).
      value = static_cast<CFTypeRef>(CFDictionaryGetValue(values, key));
    }
    genOSXPrefValues(value, r, results, 0);
    if (forced) {
      CFRelease(value);
    }
  }

  CFRelease(values);
  CFRelease(keys);
}
Esempio n. 24
-1
void genIOMediaDevice(const io_service_t& device,
                      std::vector<std::string>& whole_devices,
                      QueryData& results) {
  Row r;

  // Get the device properties
  CFMutableDictionaryRef properties;
  IORegistryEntryCreateCFProperties(
      device, &properties, kCFAllocatorDefault, kNilOptions);

  r["uuid"] = getIOKitProperty(properties, "UUID");
  r["name"] = "/dev/" + getIOKitProperty(properties, "BSD Name");
  r["size"] = getIOKitProperty(properties, "Size");

  auto type = getIOKitProperty(properties, "Whole");
  if (type == "1") {
    // The "Whole" property applies to the entire disk entry, not partitions.
    whole_devices.push_back(r["name"]);
  } else {
    // Otherwise search the list of whole disks to find the node parent.
    for (const auto& parent : whole_devices) {
      if (r.at("name").find(parent) == 0) {
        r["parent"] = parent;
      }
    }
  }

  // This is the IOKit name, which is the device's label.
  io_name_t name;
  auto kr = IORegistryEntryGetName(device, name);
  if (kr == KERN_SUCCESS && (char*)name != nullptr) {
    r["label"] = std::string(name);
  }

  // Remaining details come from the Disk Arbitration service.
  DASessionRef session = DASessionCreate(kCFAllocatorDefault);
  CFDictionaryRef details;
  if (session != nullptr) {
    auto disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, session, device);
    if (disk != nullptr) {
      details = DADiskCopyDescription(disk);
      if (details != nullptr) {
        r["vendor"] =
            getIOKitProperty((CFMutableDictionaryRef)details, "DADeviceVendor");
        r["model"] =
            getIOKitProperty((CFMutableDictionaryRef)details, "DADeviceModel");
        r["type"] = getIOKitProperty((CFMutableDictionaryRef)details,
                                     "DADeviceProtocol");
        CFRelease(details);
      }
      CFRelease(disk);
    }
    CFRelease(session);
  }

  results.push_back(r);
  CFRelease(properties);
}