2014-12-18 18:50:47 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-03-22 07:38:11 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2014-12-18 18:50:47 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2015-03-22 07:38:11 +00:00
|
|
|
|
2014-08-29 07:36:33 +00:00
|
|
|
#include <climits>
|
2014-07-31 00:35:19 +00:00
|
|
|
#include <ctime>
|
2015-01-12 20:53:05 +00:00
|
|
|
#include <random>
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-12-03 23:14:02 +00:00
|
|
|
#include <osquery/config.h>
|
|
|
|
#include <osquery/core.h>
|
|
|
|
#include <osquery/database.h>
|
|
|
|
#include <osquery/flags.h>
|
|
|
|
#include <osquery/logger.h>
|
|
|
|
#include <osquery/sql.h>
|
|
|
|
#include <osquery/scheduler.h>
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
namespace osquery {
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2015-02-17 08:36:20 +00:00
|
|
|
FLAG(string,
|
|
|
|
host_identifier,
|
|
|
|
"hostname",
|
2015-03-22 07:38:11 +00:00
|
|
|
"Field used to identify the host running osquery (hostname, uuid)");
|
2014-11-04 02:08:13 +00:00
|
|
|
|
2015-02-17 08:36:20 +00:00
|
|
|
FLAG(int32, schedule_splay_percent, 10, "Percent to splay config times");
|
2015-01-12 20:53:05 +00:00
|
|
|
|
2014-11-25 16:47:32 +00:00
|
|
|
Status getHostIdentifier(std::string& ident) {
|
|
|
|
std::shared_ptr<DBHandle> db;
|
|
|
|
try {
|
2014-12-01 23:02:40 +00:00
|
|
|
db = DBHandle::getInstance();
|
2015-01-02 05:55:10 +00:00
|
|
|
} catch (const std::runtime_error& e) {
|
2014-11-25 16:47:32 +00:00
|
|
|
return Status(1, e.what());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FLAGS_host_identifier == "uuid") {
|
2014-11-04 02:08:13 +00:00
|
|
|
std::vector<std::string> results;
|
|
|
|
auto status = db->Scan(kConfigurations, results);
|
|
|
|
|
|
|
|
if (!status.ok()) {
|
|
|
|
LOG(ERROR) << "Could not access database, using hostname as the host "
|
|
|
|
"identifier.";
|
2014-11-25 16:47:32 +00:00
|
|
|
ident = osquery::getHostname();
|
|
|
|
return Status(0, "OK");
|
2014-11-04 02:08:13 +00:00
|
|
|
}
|
|
|
|
|
2014-11-25 16:47:32 +00:00
|
|
|
if (std::find(results.begin(), results.end(), "hostIdentifier") !=
|
|
|
|
results.end()) {
|
|
|
|
status = db->Get(kConfigurations, "hostIdentifier", ident);
|
2014-11-04 02:08:13 +00:00
|
|
|
if (!status.ok()) {
|
|
|
|
LOG(ERROR) << "Could not access database, using hostname as the host "
|
|
|
|
"identifier.";
|
2014-11-25 16:47:32 +00:00
|
|
|
ident = osquery::getHostname();
|
2014-11-04 02:08:13 +00:00
|
|
|
}
|
2014-11-25 16:47:32 +00:00
|
|
|
return status;
|
2014-11-04 02:08:13 +00:00
|
|
|
} else {
|
|
|
|
// There was no uuid stored in the database, generate one and store it.
|
2014-11-25 16:47:32 +00:00
|
|
|
ident = osquery::generateHostUuid();
|
|
|
|
LOG(INFO) << "Using uuid " << ident << " to identify this host.";
|
2014-12-02 22:09:37 +00:00
|
|
|
return db->Put(kConfigurations, "hostIdentifier", ident);
|
2014-11-04 02:08:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// use the hostname as the default machine identifier
|
2014-11-25 16:47:32 +00:00
|
|
|
ident = osquery::getHostname();
|
|
|
|
return Status(0, "OK");
|
2014-11-04 02:08:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-02 05:55:10 +00:00
|
|
|
void launchQuery(const OsqueryScheduledQuery& query) {
|
|
|
|
LOG(INFO) << "Executing query: " << query.query;
|
|
|
|
int unix_time = std::time(0);
|
|
|
|
auto sql = SQL(query.query);
|
|
|
|
if (!sql.ok()) {
|
|
|
|
LOG(ERROR) << "Error executing query (" << query.query
|
|
|
|
<< "): " << sql.getMessageString();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto dbQuery = Query(query);
|
|
|
|
DiffResults diff_results;
|
|
|
|
auto status = dbQuery.addNewResults(sql.rows(), diff_results, unix_time);
|
|
|
|
if (!status.ok()) {
|
|
|
|
LOG(ERROR) << "Error adding new results to database: " << status.what();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diff_results.added.size() == 0 && diff_results.removed.size() == 0) {
|
|
|
|
// No diff results or events to emit.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScheduledQueryLogItem item;
|
|
|
|
Status s;
|
|
|
|
|
|
|
|
item.diffResults = diff_results;
|
|
|
|
item.name = query.name;
|
|
|
|
|
|
|
|
std::string ident;
|
|
|
|
s = getHostIdentifier(ident);
|
|
|
|
if (s.ok()) {
|
|
|
|
item.hostIdentifier = ident;
|
|
|
|
} else {
|
|
|
|
LOG(ERROR) << "Error getting the host identifier";
|
|
|
|
if (ident.empty()) {
|
|
|
|
ident = "<unknown>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item.unixTime = osquery::getUnixTime();
|
|
|
|
item.calendarTime = osquery::getAsciiTime();
|
|
|
|
|
|
|
|
LOG(INFO) << "Found results for query " << query.name
|
|
|
|
<< " for host: " << ident;
|
|
|
|
s = logScheduledQueryLogItem(item);
|
|
|
|
if (!s.ok()) {
|
|
|
|
LOG(ERROR) << "Error logging the results of query \"" << query.query << "\""
|
|
|
|
<< ": " << s.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:17:48 +00:00
|
|
|
void launchQueries(const std::vector<OsqueryScheduledQuery>& queries,
|
2014-09-10 21:28:46 +00:00
|
|
|
const int64_t& second) {
|
2014-09-16 06:07:03 +00:00
|
|
|
for (const auto& q : queries) {
|
|
|
|
if (second % q.interval == 0) {
|
2015-01-02 05:55:10 +00:00
|
|
|
launchQuery(q);
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 20:53:05 +00:00
|
|
|
int splayValue(int original, int splayPercent) {
|
|
|
|
if (splayPercent <= 0 || splayPercent > 100) {
|
|
|
|
return original;
|
|
|
|
}
|
|
|
|
|
|
|
|
float percent_to_modify_by = (float)splayPercent / 100;
|
|
|
|
int possible_difference = original * percent_to_modify_by;
|
|
|
|
int max_value = original + possible_difference;
|
|
|
|
int min_value = original - possible_difference;
|
|
|
|
|
|
|
|
if (max_value == min_value) {
|
|
|
|
return max_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::default_random_engine generator;
|
|
|
|
std::uniform_int_distribution<int> distribution(min_value, max_value);
|
|
|
|
return distribution(generator);
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:26:16 +00:00
|
|
|
void initializeScheduler() {
|
|
|
|
DLOG(INFO) << "osquery::initializeScheduler";
|
2014-08-29 00:33:03 +00:00
|
|
|
time_t t = time(0);
|
2014-08-30 11:06:21 +00:00
|
|
|
struct tm* local = localtime(&t);
|
2014-09-10 21:28:46 +00:00
|
|
|
unsigned long int second = local->tm_sec;
|
2015-01-02 05:55:10 +00:00
|
|
|
|
2014-08-29 07:36:33 +00:00
|
|
|
#ifdef OSQUERY_TEST_DAEMON
|
2014-09-10 21:28:46 +00:00
|
|
|
// if we're testing the daemon, only iterate through 15 "seconds"
|
|
|
|
static unsigned long int stop_at = second + 15;
|
2014-08-29 07:36:33 +00:00
|
|
|
#else
|
|
|
|
// if this is production, count forever
|
2014-08-30 11:26:40 +00:00
|
|
|
static unsigned long int stop_at = ULONG_MAX;
|
2014-08-29 07:36:33 +00:00
|
|
|
#endif
|
2015-01-02 05:55:10 +00:00
|
|
|
|
2015-01-12 20:53:05 +00:00
|
|
|
// Iterate over scheduled queryies and add a splay to each.
|
2015-03-04 02:40:24 +00:00
|
|
|
auto schedule = Config::getScheduledQueries();
|
2015-01-12 20:53:05 +00:00
|
|
|
for (auto& q : schedule) {
|
|
|
|
auto old_interval = q.interval;
|
|
|
|
auto new_interval = splayValue(old_interval, FLAGS_schedule_splay_percent);
|
|
|
|
VLOG(1) << "Splay changing the interval for " << q.name << " from "
|
|
|
|
<< old_interval << " to " << new_interval;
|
|
|
|
q.interval = new_interval;
|
|
|
|
}
|
|
|
|
|
2014-09-10 21:28:46 +00:00
|
|
|
for (; second <= stop_at; ++second) {
|
2015-01-12 20:53:05 +00:00
|
|
|
launchQueries(schedule, second);
|
2015-01-02 05:55:10 +00:00
|
|
|
::sleep(1);
|
2014-08-29 00:33:03 +00:00
|
|
|
}
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
2014-08-15 07:25:30 +00:00
|
|
|
}
|