-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-#include <future>
#include <map>
#include <memory>
-#include <mutex>
-#include <string>
-#include <utility>
#include <vector>
+#include <osquery/flags.h>
+#include <osquery/scheduler.h>
#include <osquery/status.h>
namespace osquery {
-/**
- * @brief represents the relevant parameters of a scheduled query.
- *
- * Within the context of osqueryd, a scheduled query may have many relevant
- * attributes. Those attributes are represented in this data structure.
- */
-struct OsqueryScheduledQuery {
- /// name represents the "name" of a query.
- std::string name;
-
- /// query represents the actual SQL query.
- std::string query;
-
- /// interval represents how often the query should be executed, in minutes.
- int interval;
-
- /// equals operator
- bool operator==(const OsqueryScheduledQuery& comp) const {
- return (comp.name == name) && (comp.query == query) &&
- (comp.interval == interval);
- }
-
- /// not equals operator
- bool operator!=(const OsqueryScheduledQuery& comp) const {
- return !(*this == comp);
- }
-};
+/// The builder or invoker may change the default config plugin.
+DECLARE_string(config_retriever);
/**
* @brief A native representation of osquery configuration data.
static std::shared_ptr<Config> getInstance();
/**
+ * @brief Call the genConfig method of the config retriever plugin.
+ *
+ * This may perform a resource load such as TCP request or filesystem read.
+ */
+ Status load();
+
+ /**
* @brief Get a vector of all scheduled queries.
*
* @code{.cpp}
std::vector<OsqueryScheduledQuery> getScheduledQueries();
/**
- * @brief Calculate a splayed integer based on a variable splay percentage
+ * @brief Calculate the has of the osquery config
*
- * The value of splayPercent must be between 1 and 100. If it's not, the
- * value of original will be returned.
- *
- * @param original The original value to be modified
- * @param splayPercent The percent in which to splay the original value by
+ * @return The MD5 of the osquery config
+ */
+ Status getMD5(std::string& hashString);
+
+ /**
+ * @brief Check to ensure that the config is accessible and properly
+ * formatted
*
- * @return The modified version of original
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
*/
- static int splayValue(int original, int splayPercent);
+ static osquery::Status checkConfig();
private:
/**
* Since instances of Config should only be created via getInstance(),
* Config's constructor is private
*/
- Config();
+ Config() {}
/**
* @brief Uses the specified config retriever to populate a config struct.
*/
static osquery::Status genConfig(OsqueryConfig& conf);
+ /**
+ * @brief Uses the specified config retriever to populate a string with the
+ * config JSON.
+ *
+ * Internally, genConfig checks to see if there was a config retriever
+ * specified on the command-line. If there was, it checks to see if that
+ * config retriever actually exists. If it does, it gets used to generate
+ * configuration data. If it does not, an error is logged.
+ *
+ * If no config retriever was specified, the config retriever represented by
+ * kDefaultConfigRetriever is used.
+ *
+ * @param conf a reference to a string which will be populated by the config
+ * retriever in use.
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
+ */
+ static osquery::Status genConfig(std::string& conf);
+
private:
/**
* @brief the private member that stores the raw osquery config data in a
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
/////////////////////////////////////////////////////////////////////////////
friend class DBHandleTests;
- friend class QueryTests;
+ friend class EventsTests;
friend class EventsDatabaseTests;
+ friend class QueryTests;
};
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <gtest/gtest_prod.h>
-#include <osquery/config.h>
#include <osquery/database/db_handle.h>
#include <osquery/database/results.h>
+#include <osquery/scheduler.h>
#include <osquery/status.h>
namespace osquery {
* @param q an OsqueryScheduledQuery struct which represents the query which
* you would like to interact with
*/
- explicit Query(osquery::OsqueryScheduledQuery q) : query_(q) {}
+ explicit Query(OsqueryScheduledQuery q) : query_(q) {}
/////////////////////////////////////////////////////////////////////////////
// Getters and setters
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
Status deserializeHistoricalQueryResultsJSON(const std::string& json,
HistoricalQueryResults& r);
-/////////////////////////////////////////////////////////////////////////////
-// ScheduledQueryLogItem
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * @brief A data structure which represents data to log in the event of an
- * operating system state change
- *
- * When a scheduled query yields new results, we need to log that information
- * to our upstream logging receiver. The data that needs to be logged is the
- * entire DiffResults set as well as some additional metadata.
- */
-struct ScheduledQueryLogItem {
- /// The data which was changed as a result of the scheduled query
- DiffResults diffResults;
-
- /// The name of the scheduled query
- std::string name;
-
- /// The identifier (hostname, or uuid) of the host on which the query was
- /// executed
- std::string hostIdentifier;
-
- /// The time that the query was executed, in unix time
- int unixTime;
-
- /// The time that the query was executed, in ASCII
- std::string calendarTime;
-
- /// equals operator
- bool operator==(const ScheduledQueryLogItem& comp) const {
- return (comp.diffResults == diffResults) && (comp.name == name);
- }
-
- /// not equals operator
- bool operator!=(const ScheduledQueryLogItem& comp) const {
- return !(*this == comp);
- }
-};
-
-/**
- * @brief Serialize a ScheduledQueryLogItem object into a property tree
- *
- * @param i the ScheduledQueryLogItem to serialize
- * @param tree a reference to a property tree which, if all operations are
- * completed successfully, the contents of ScheduledQueryLogItem will be
- * serialized into
- *
- * @return an instance of osquery::Status, indicating the success or failure
- * of the operation
- */
-Status serializeScheduledQueryLogItem(const ScheduledQueryLogItem& i,
- boost::property_tree::ptree& tree);
-
-/**
- * @brief Serialize a ScheduledQueryLogItem object into a JSON string
- *
- * @param i the ScheduledQueryLogItem to serialize
- * @param json a reference to a string which, if all operations are completed
- * successfully, the contents of ScheduledQueryLogItem will be serialized into
- *
- * @return an instance of osquery::Status, indicating the success or failure
- * of the operation
- */
-Status serializeScheduledQueryLogItemJSON(const ScheduledQueryLogItem& i,
- std::string& json);
-
-/**
- * @brief Serialize a ScheduledQueryLogItem object into a property tree
- * of events, a list of actions.
- *
- * @param item the ScheduledQueryLogItem to serialize
- * @param tree a reference to a property tree which, if all operations are
- * completed successfully, the contents of ScheduledQueryLogItem will be
- * serialized into
- *
- * @return an instance of osquery::Status, indicating the success or failure
- * of the operation
- */
-Status serializeScheduledQueryLogItemAsEvents(
- const ScheduledQueryLogItem& item, boost::property_tree::ptree& tree);
-
-/**
- * @brief Serialize a ScheduledQueryLogItem object into a JSON string of events,
- * a list of actions.
- *
- * @param i the ScheduledQueryLogItem to serialize
- * @param json a reference to a string which, if all operations are completed
- * successfully, the contents of ScheduledQueryLogItem will be serialized into
- *
- * @return an instance of osquery::Status, indicating the success or failure
- * of the operation
- */
-Status serializeScheduledQueryLogItemAsEventsJSON(
- const ScheduledQueryLogItem& i, std::string& json);
-
/**
* @brief Add a Row to a QueryData if the Row hasn't appeared in the QueryData
* already
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <osquery/database.h>
#include <osquery/registry.h>
#include <osquery/status.h>
+#include <osquery/tables.h>
namespace osquery {
struct Subscription;
-class EventPublisher;
-class EventSubscriber;
+template <class SC, class EC> class EventPublisher;
+template <class PUB> class EventSubscriber;
+class EventFactory;
typedef const std::string EventPublisherID;
+typedef const std::string EventSubscriberID;
typedef const std::string EventID;
typedef uint32_t EventContextID;
typedef uint32_t EventTime;
* subscriptioning/listening handles, etc.
*
* Linux `inotify` should implement a SubscriptionContext that subscriptions
- * filesystem events based on a filesystem path. `libpcap` will subscription on
- * networking protocols at various stacks. Process creation may subscription on
+ * filesystem events based on a filesystem path. `libpcap` will subscribe on
+ * networking protocols at various stacks. Process creation may subscribe on
* process name, parent pid, etc.
*/
struct SubscriptionContext {};
* @brief An EventSubscriber EventCallback method will receive an EventContext.
*
* The EventContext contains the event-related data supplied by an
- * EventPublisher when the event occures. If a subscriptioning EventSubscriber
- * is should be called for the event the EventSubscriber%'s EventCallback is
+ * EventPublisher when the event occures. If a subscribing EventSubscriber
+ * would be called for the event, the EventSubscriber%'s EventCallback is
* passed an EventContext.
*/
struct EventContext {
};
typedef std::shared_ptr<Subscription> SubscriptionRef;
-typedef std::shared_ptr<EventPublisher> EventPublisherRef;
+typedef EventPublisher<SubscriptionContext, EventContext> BaseEventPublisher;
+typedef std::shared_ptr<BaseEventPublisher> EventPublisherRef;
typedef std::shared_ptr<SubscriptionContext> SubscriptionContextRef;
typedef std::shared_ptr<EventContext> EventContextRef;
-typedef std::shared_ptr<EventSubscriber> EventSubscriberRef;
+typedef std::shared_ptr<EventSubscriber<BaseEventPublisher>> EventSubscriberRef;
-typedef std::function<Status(EventContextRef, bool)> EventCallback;
+/// Use a single placeholder for the EventContextRef passed to EventCallback.
+using std::placeholders::_1;
+typedef std::function<Status(const EventContextRef&)> EventCallback;
/// An EventPublisher must track every subscription added.
typedef std::vector<SubscriptionRef> SubscriptionVector;
-/// The EventFactory tracks every EventPublisher and the name it specifies.
-typedef std::map<EventPublisherID, EventPublisherRef> EventPublisherMap;
-
/// The set of search-time binned lookup tables.
extern const std::vector<size_t> kEventTimeLists;
/**
- * @brief Helper type casting methods for EventPublisher classes.
- *
- * A new osquery EventPublisher should subclass EventPublisher and use the
- * following:
- *
- * @code{.cpp}
- * #include <osquery/events.h>
- *
- * class MyEventPublisher: public EventPublisher {
- * DECLARE_EVENTPUBLISHER(MyEventPublisher, MySubscriptionContext,
- * MyEventContext);
- * }
- * @endcode
- *
- * This assumes new EventPublisher%s will always include a custom
- * SubscriptionContext and EventContext. In the above example
- * MySubscriptionContext allows EventSubscriber%s to downselect or customize
- * what events to handle. And MyEventContext includes fields specific to the
- * new EventPublisher.
+ * @brief DECLARE_PUBLISHER supplies needed boilerplate code that applies a
+ * string-type EventPublisherID to identify the publisher declaration.
*/
-#define DECLARE_EVENTPUBLISHER(TYPE, MONITOR, EVENT) \
- public: \
- EventPublisherID type() const { return #TYPE; } \
- bool shouldFire(const SubscriptionContextRef mc, const EventContextRef ec) { \
- if (#MONITOR == "SubscriptionContext" && #EVENT == "EventContext") \
- return true; \
- return shouldFire(getSubscriptionContext(mc), getEventContext(ec)); \
- } \
- static std::shared_ptr<EVENT> getEventContext(EventContextRef context) { \
- return std::static_pointer_cast<EVENT>(context); \
- } \
- static std::shared_ptr<MONITOR> getSubscriptionContext( \
- SubscriptionContextRef context) { \
- return std::static_pointer_cast<MONITOR>(context); \
- } \
- static std::shared_ptr<EVENT> createEventContext() { \
- return std::make_shared<EVENT>(); \
- } \
- static std::shared_ptr<MONITOR> createSubscriptionContext() { \
- return std::make_shared<MONITOR>(); \
- }
+#define DECLARE_PUBLISHER(TYPE) \
+ public: \
+ EventPublisherID type() { return TYPE; }
/**
- * @brief Required getter and namespace helper methods for EventSubscriber%s.
- *
- * A new osquery `EventSubscriber` should subclass EventSubscriber with the
- * following:
- *
- * @code{.cpp}
- * #include <osquery/events.h>
- *
- * class MyEventSubscriber: public EventSubscriber {
- * DECLARE_EVENTSUBSCRIBER(MyEventSubscriber, MyEventPublisher);
- * }
- * @endcode
- *
- * EventSubscriber%s should be specific to an EventPublisher.
+ * @brief DECLARE_SUBSCRIBER supplies needed boilerplate code that applies a
+ * string-type EventSubscriberID to identify the subscriber declaration.
*/
-#define DECLARE_EVENTSUBSCRIBER(NAME, TYPE) \
- public: \
- static std::shared_ptr<NAME> getInstance() { \
- static auto q = std::shared_ptr<NAME>(new NAME()); \
- return q; \
- } \
- static QueryData genTable(osquery::tables::QueryContext& context) \
- __attribute__((used)) { \
- return getInstance()->get(0, 0); \
- } \
- \
- private: \
- EventPublisherID name() const { return #NAME; } \
- EventPublisherID type() const { return #TYPE; } \
- NAME() {}
-
-/**
- * @brief Required callin EventSubscriber method declaration helper.
- *
- * An EventSubscriber will include 1 or more EventCallback methods. Consider the
- * following flow: (1) Event occurs, (2) EventCallback is called with the
- * event details, (3) details logged, (4) details are queried.
- *
- * The above logic can be supplied in a class-like namespace with static
- * callin/callback functions:
- *
- * @code{.cpp}
- * #include <osquery/events.h>
- *
- * class MyEventSubscriber: public EventSubscriber {
- * DECLARE_EVENTSUBSCRIBER(MyEventSubscriber, MyEventPublisher);
- * DECLARE_CALLBACK(MyCallback, MyEventContext)
- *
- * Status ModuleMyCallback(EventContextID, EventTime, MyEventContext);
- * }
- * @endcode
- *
- * And then somewhere else in code the callback can be registered:
- *
- * @code{.cpp}
- * EventFactory::addSubscription("MyEventPublisher", my_subscription_context,
- * MyEventSubscriber::MyCallback);
- * @endcode
- *
- * The binding from static method, function pointer, and EventSubscriber
- * instance boilerplate code is added automatically.
- * Note: The macro will append `Module` to `MyCallback`.
- */
-#define DECLARE_CALLBACK(NAME, EVENT) \
- public: \
- static Status Event##NAME(const EventContextRef ec, bool reserved) { \
- auto ec_ = std::static_pointer_cast<EVENT>(ec); \
- return getInstance()->NAME(ec_); \
- } \
- \
- private: \
- void BindTo##NAME(const SubscriptionContextRef mc) { \
- EventFactory::addSubscription(type(), mc, Event##NAME); \
- }
-
-/**
- * @brief Bind a subscription context to a declared EventCallback for this
- *module.
- *
- * Binding refers to the association of a callback for this EventSubscriber to
- * a configured SubscriptionContext. Under the hood "binding" creates a factory
- * Subscription for the EventPublisher used by the EventSubscriber. Such that
- * when an event of the EventPublisher is fired, if the event details match the
- * specifics of the SubscriptionContext the EventSubscription%'s EventCallback
- * will be called.
- *
- * @code{.cpp}
- * #include <osquery/events.h>
- *
- * class MyEventSubscriber: public EventSubscriber {
- * DECLARE_EVENTSUBSCRIBER(MyEventSubscriber, MyEventPublisher);
- * DECLARE_CALLBACK(MyCallback, MyEventContext);
- *
- * public:
- * void init() {
- * auto mc = MyEventPublisher::createSubscriptionContext();
- * mc->requirement = "SOME_SPECIFIC_DETAIL";
- * BIND_CALLBACK(MyCallback, mc);
- * }
- * Status MyCallback(const MyEventContextRef ec) {}
- * }
- * @endcode
- *
- * The symbol `MyCallback` must match in `DECLARE_CALLBACK`, `BIND_CALLBACK` and
- * as a member of this EventSubscriber.
- *
- * @param NAME The symbol for the EventCallback method used in DECLARE_CALLBACK.
- * @param MC The SubscriptionContext to bind.
- */
-#define BIND_CALLBACK(NAME, MC) \
- EventFactory::addSubscription(type(), MC, Event##NAME);
+#define DECLARE_SUBSCRIBER(NAME) \
+ public: \
+ EventSubscriberID name() { return NAME; }
/**
* @brief A Subscription is used to configure an EventPublisher and bind a
- * callback.
+ * callback to a SubscriptionContext.
*
* A Subscription is the input to an EventPublisher when the EventPublisher
- * decides on the scope and details of the events it watches and generates.
+ * decides on the scope and details of the events it watches/generates.
* An example includes a filesystem change event. A subscription would include
* a path with optional recursion and attribute selectors as well as a callback
* function to fire when an event for that path and selector occurs.
static SubscriptionRef create() { return std::make_shared<Subscription>(); }
- static SubscriptionRef create(const SubscriptionContextRef mc,
+ static SubscriptionRef create(const SubscriptionContextRef& mc,
EventCallback ec = 0) {
auto subscription = std::make_shared<Subscription>();
subscription->context = mc;
}
};
-/**
- * @brief Generate OS events of a type (FS, Network, Syscall, ioctl).
- *
- * A 'class' of OS events is abstracted into an EventPublisher responsible for
- * remaining as agile as possible given a known-set of subscriptions.
- *
- * The lifecycle of an EventPublisher may include, `setUp`, `configure`, `run`,
- * `tearDown`, and `fire`. `setUp` and `tearDown` happen when osquery starts and
- * stops either as a daemon or interactive shell. `configure` is a pseudo-start
- * called every time a Subscription is added. EventPublisher%s can adjust their
- * scope/agility specific to each added subscription by overriding
- *`addSubscription`,
- * and or globally in `configure`.
- *
- * Not all EventPublisher%s leverage pure async OS APIs, and most will require a
- * run loop either polling with a timeout on a descriptor or for a change. When
- * osquery initializes the EventFactory will optionally create a thread for each
- * EventPublisher using `run` as the thread's entrypoint. This is called in a
- * within-thread loop where returning a FAILED status ends the run loop and
- * shuts down the thread.
- *
- * To opt-out of polling in a thread consider the following run implementation:
- *
- * @code{.cpp}
- * Status run() { return Status(1, "Not Implemented") }
- * @endcode
- *
- * The final lifecycle component, `fire` will iterate over the EventPublisher
- * Subscription%s and call `shouldFire` for each, using the EventContext fired.
- * The `shouldFire` method should check the subscription-specific selectors and
- * only call the Subscription%'s callback function is the EventContext
- * (thus event) matches.
- */
-class EventPublisher {
+class EventPublisherCore {
public:
/**
* @brief A new Subscription was added, potentially change state based on all
* When `setUp` is called the EventPublisher is running in a dedicated thread
* and may manage/allocate/wait for resources.
*/
- virtual Status setUp() { return Status(0, "Not used."); }
+ virtual Status setUp() { return Status(0, "Not used"); }
/**
* @brief Perform handle closing, resource cleanup.
* @return A SUCCESS status will immediately call `run` again. A FAILED status
* will exit the run loop and the thread.
*/
- virtual Status run();
+ virtual Status run() { return Status(1, "No runloop required"); }
/**
* @brief A new EventSubscriber is subscriptioning events of this
*
* @return If the Subscription is not appropriate (mismatched type) fail.
*/
- virtual Status addSubscription(const SubscriptionRef subscription) {
+ virtual Status addSubscription(const SubscriptionRef& subscription) {
subscriptions_.push_back(subscription);
return Status(0, "OK");
}
+ /**
+ * @brief The generic check loop to call SubscriptionContext callback methods.
+ *
+ * It is NOT recommended to override `fire`. The simple logic of enumerating
+ * the Subscription%s and using `shouldFire` is more appropraite.
+ *
+ * @param ec The EventContext created and fired by the EventPublisher.
+ * @param time The most accurate time associated with the event.
+ */
+ void fire(const EventContextRef& ec, EventTime time = 0);
+
/// Number of Subscription%s watching this EventPublisher.
size_t numSubscriptions() { return subscriptions_.size(); }
size_t numEvents() { return next_ec_id_; }
/// Overriding the EventPublisher constructor is not recommended.
- EventPublisher() : next_ec_id_(0){};
- virtual ~EventPublisher() {}
+ EventPublisherCore() : next_ec_id_(0), ending_(false){};
+ virtual ~EventPublisherCore() {}
/// Return a string identifier associated with this EventPublisher.
- virtual EventPublisherID type() const = 0;
-
- /// Return a string identifier for the given EventPublisher symbol.
- template <typename T>
- static EventPublisherID type() {
- const auto& event_pub = new T();
- auto type_id = event_pub->type();
- delete event_pub;
- return type_id;
- }
+ virtual EventPublisherID type() { return "publisher"; }
+
+ void shouldEnd(bool should_end) { ending_ = should_end; }
+ bool isEnding() { return ending_; }
+
+ protected:
+ /// The internal fire method used by the typed EventPublisher.
+ virtual void fireCallback(const SubscriptionRef& sub,
+ const EventContextRef& ec) = 0;
+
+ /// The EventPublisher will keep track of Subscription%s that contain callins.
+ SubscriptionVector subscriptions_;
+
+ /// An Event ID is assigned by the EventPublisher within the EventContext.
+ /// This is not used to store event date in the backing store.
+ EventContextID next_ec_id_;
+
+ private:
+ /// Set ending to True to cause event type run loops to finish.
+ bool ending_;
+
+ /// A lock for incrementing the next EventContextID.
+ boost::mutex ec_id_lock_;
+
+ private:
+ FRIEND_TEST(EventsTests, test_event_pub);
+ FRIEND_TEST(EventsTests, test_fire_event);
+};
+
+/**
+ * @brief Generate OS events of a type (FS, Network, Syscall, ioctl).
+ *
+ * A 'class' of OS events is abstracted into an EventPublisher responsible for
+ * remaining as agile as possible given a known-set of subscriptions.
+ *
+ * The lifecycle of an EventPublisher may include, `setUp`, `configure`, `run`,
+ * `tearDown`, and `fire`. `setUp` and `tearDown` happen when osquery starts and
+ * stops either as a daemon or interactive shell. `configure` is a pseudo-start
+ * called every time a Subscription is added. EventPublisher%s can adjust their
+ * scope/agility specific to each added subscription by overriding
+ *`addSubscription`, and/or globally in `configure`.
+ *
+ * Not all EventPublisher%s leverage pure async OS APIs, and most will require a
+ * run loop either polling with a timeout on a descriptor or for a change. When
+ * osquery initializes the EventFactory will optionally create a thread for each
+ * EventPublisher using `run` as the thread's entrypoint. `run` is called in a
+ * within-thread loop where returning a FAILED status ends the run loop and
+ * shuts down the thread.
+ *
+ * To opt-out of polling in a thread, consider the following run implementation:
+ *
+ * @code{.cpp}
+ * Status run() { return Status(1, "Not Implemented"); }
+ * @endcode
+ *
+ * The final lifecycle component, `fire` will iterate over the EventPublisher
+ * Subscription%s and call `shouldFire` for each, using the EventContext fired.
+ * The `shouldFire` method should check the subscription-specific selectors and
+ * only call the Subscription%'s callback function if the EventContext
+ * (thus event) matches.
+ */
+template <typename SC, typename EC>
+class EventPublisher : public EventPublisherCore {
+ public:
+ /// A nested helper typename for the templated SubscriptionContextRef.
+ typedef typename std::shared_ptr<SC> SCRef;
+ /// A nested helper typename for the templated EventContextRef.
+ typedef typename std::shared_ptr<EC> ECRef;
public:
+ /// Up-cast a base EventContext reference to the templated ECRef.
+ static ECRef getEventContext(const EventContextRef& ec) {
+ return std::static_pointer_cast<EC>(ec);
+ }
+
+ /// Up-cast a base SubscriptionContext reference to the templated SCRef.
+ static SCRef getSubscriptionContext(const SubscriptionContextRef& sc) {
+ return std::static_pointer_cast<SC>(sc);
+ }
+
+ /// Create a EventContext based on the templated type.
+ static ECRef createEventContext() { return std::make_shared<EC>(); }
+
+ /// Create a SubscriptionContext based on the templated type.
+ static SCRef createSubscriptionContext() { return std::make_shared<SC>(); }
+
+ /// A simple EventPublisher type accessor.
+ template <class PUB>
+ static EventPublisherID getType() {
+ auto pub = std::make_shared<PUB>();
+ return pub->type();
+ }
+
+ protected:
/**
- * @brief The generic check loop to call SubscriptionContext callback methods.
+ * @brief The internal `fire` phase of publishing.
*
- * It is NOT recommended to override `fire`. The simple logic of enumerating
- * the Subscription%s and using `shouldFire` is more appropraite.
+ * This is a template-generated method that up-casts the generic fired
+ * event/subscription contexts, and calls the callback if the event should
+ * fire given a scription.
*
- * @param ec The EventContext created and fired by the EventPublisher.
- * @param time The most accurate time associated with the event.
+ * @param sub The SubscriptionContext and optional EventCallback.
+ * @param ec The event that was fired.
*/
- void fire(const EventContextRef ec, EventTime time = 0);
+ void fireCallback(const SubscriptionRef& sub, const EventContextRef& ec) {
+ auto pub_sc = getSubscriptionContext(sub->context);
+ auto pub_ec = getEventContext(ec);
+ if (shouldFire(pub_sc, pub_ec) && sub->callback != nullptr) {
+ sub->callback(pub_ec);
+ }
+ }
protected:
/**
*
* @return should the Subscription%'s EventCallback be called for this event.
*/
- virtual bool shouldFire(const SubscriptionContextRef mc,
- const EventContextRef ec);
-
- protected:
- /// The EventPublisher will keep track of Subscription%s that contain callins.
- SubscriptionVector subscriptions_;
-
- /// An Event ID is assigned by the EventPublisher within the EventContext.
- /// This is not used to store event date in the backing store.
- EventContextID next_ec_id_;
-
- private:
- /// A lock for incrementing the next EventContextID.
- boost::mutex ec_id_lock_;
+ virtual bool shouldFire(const SCRef& sc, const ECRef& ec) { return true; }
private:
+ FRIEND_TEST(EventsTests, test_event_sub_subscribe);
+ FRIEND_TEST(EventsTests, test_event_sub_context);
FRIEND_TEST(EventsTests, test_fire_event);
};
/**
- * @brief An interface binding Subscriptions, event response, and table
- *generation.
+ * @brief A factory for associating event generators to EventPublisherID%s.
*
- * Use the EventSubscriber interface when adding event subscriptions and
- * defining callin functions. The EventCallback is usually a member function
- * for an EventSubscriber. The EventSubscriber interface includes a very
- * important `add` method that abstracts the needed event to backing store
- * interaction.
+ * This factory both registers new event types and the subscriptions that use
+ * them. An EventPublisher is also a factory, the single event factory arbitates
+ * Subscription creatating and management for each associated EventPublisher.
*
- * Storing event data in the backing store must match a table spec for queries.
- * Small overheads exist that help query-time indexing and lookups.
+ * Since event types may be plugins, they are created using the factory.
+ * Since subscriptions may be configured/disabled they are also factory-managed.
*/
-class EventSubscriber {
+class EventFactory {
public:
- /// Called after EventPublisher `setUp`. Add all Subscription%s here.
+ /// Access to the EventFactory instance.
+ static EventFactory& getInstance();
+
+ /// A factory event publisher generator, simplify boilerplate code.
+ template <class PUB>
+ static EventPublisherRef createEventPublisher() {
+ auto pub = std::make_shared<PUB>();
+ auto base_pub = reinterpret_cast<EventPublisherRef&>(pub);
+ return base_pub;
+ }
+
+ /// A factory event subscriber generator, simplify boilerplate code.
+ template <class SUB>
+ static EventSubscriberRef createEventSubscriber() {
+ auto sub = std::make_shared<SUB>();
+ auto base_sub = reinterpret_cast<EventSubscriberRef&>(sub);
+ return base_sub;
+ }
+
/**
- * @brief Add Subscription%s to the EventPublisher this module will act on.
+ * @brief Add an EventPublisher to the factory.
*
- * When the EventSubscriber%'s `init` method is called you are assured the
- * EventPublisher has `setUp` and is ready to subscription for events.
+ * The registration is mostly abstracted using osquery's registery.
*/
- virtual void init() {}
+ template <class T>
+ static Status registerEventPublisher() {
+ auto pub = std::make_shared<T>();
+ return registerEventPublisher(pub);
+ }
/**
- * @brief Suggested entrypoint for table generation.
+ * @brief Add an EventPublisher to the factory.
*
- * The EventSubscriber is a convention that removes a lot of boilerplate event
- * subscriptioning and acting. The `genTable` static entrypoint is the
- * suggested method for table specs.
+ * The registration is mostly abstracted using osquery's registery.
*
- * @return The query-time table data, retrieved from a backing store.
+ * @param event_pub If for some reason the caller needs access to the
+ * EventPublisher instance they can register-by-instance.
+ *
+ * Access to the EventPublisher instance is not discouraged, but using the
+ * EventFactory `getEventPublisher` accessor is encouraged.
+ */
+ template <class T>
+ static Status registerEventPublisher(std::shared_ptr<T> pub) {
+ auto base_pub = reinterpret_cast<EventPublisherRef&>(pub);
+ return registerEventPublisher(base_pub);
+ }
+
+ /// Once the event publisher has been down-casted, call it's API.
+ static Status registerEventPublisher(const EventPublisherRef& pub);
+
+ /**
+ * @brief Add an EventSubscriber to the factory.
+ *
+ * The registration is mostly abstracted using osquery's registery.
+ */
+ template <class T>
+ static Status registerEventSubscriber() {
+ auto sub = std::make_shared<T>();
+ return registerEventSubscriber(sub);
+ }
+
+ /**
+ * @brief Add an EventSubscriber to the factory.
+ *
+ * The registration is mostly abstracted using osquery's registery.
+ *
+ * @param sub If the caller must access the EventSubscriber instance
+ * control may be passed to the registry.
+ *
+ * Access to the EventSubscriber instance outside of the within-instance
+ * table generation method and set of EventCallback%s is discouraged.
+ */
+ template <class T>
+ static Status registerEventSubscriber(std::shared_ptr<T> sub) {
+ auto base_sub = reinterpret_cast<EventSubscriberRef&>(sub);
+ return registerEventSubscriber(base_sub);
+ }
+
+ /// Once the event subscriber has been down-casted, call it's API.
+ static Status registerEventSubscriber(const EventSubscriberRef& sub);
+
+ /**
+ * @brief Add a SubscriptionContext and EventCallback Subscription to an
+ *EventPublisher.
+ *
+ * Create a Subscription from a given SubscriptionContext and EventCallback
+ * and add that Subscription to the EventPublisher assosicated identiter.
+ *
+ * @param type_id The string for an EventPublisher receiving the Subscription.
+ * @param mc A SubscriptionContext related to the EventPublisher.
+ * @param cb When the EventPublisher fires an event the SubscriptionContext
+ * will be evaluated, if the event matches optional specifics in the context
+ * this callback function will be called. It should belong to an
+ * EventSubscription.
+ *
+ * @return Was the SubscriptionContext appropriate for the EventPublisher.
+ */
+ static Status addSubscription(EventPublisherID& type_id,
+ const SubscriptionContextRef& mc,
+ EventCallback cb = 0);
+
+ /// Add a Subscription by templating the EventPublisher, using a
+ /// SubscriptionContext.
+ template <typename PUB>
+ static Status addSubscription(const SubscriptionContextRef& mc,
+ EventCallback cb = 0) {
+ return addSubscription(BaseEventPublisher::getType<PUB>(), mc, cb);
+ }
+
+ /// Add a Subscription using a caller Subscription instance.
+ static Status addSubscription(EventPublisherID& type_id,
+ const SubscriptionRef& subscription);
+
+ /// Get the total number of Subscription%s across ALL EventPublisher%s.
+ static size_t numSubscriptions(EventPublisherID& type_id);
+
+ /// Get the number of EventPublishers.
+ static size_t numEventPublishers() {
+ return EventFactory::getInstance().event_pubs_.size();
+ }
+
+ /**
+ * @brief Halt the EventPublisher run loop and call its `tearDown`.
+ *
+ * Any EventSubscriber%s with Subscription%s for this EventPublisher will
+ * become useless. osquery instanciators MUST deregister events.
+ * EventPublisher%s assume they can hook/trampoline, which requires cleanup.
+ *
+ * @param event_pub The string label for the EventPublisher.
+ *
+ * @return Did the EventPublisher deregister cleanly.
+ */
+ static Status deregisterEventPublisher(const EventPublisherRef& pub);
+
+ /// Deregister an EventPublisher by EventPublisherID.
+ static Status deregisterEventPublisher(EventPublisherID& type_id);
+
+ /// Deregister all EventPublisher%s.
+ static Status deregisterEventPublishers();
+
+ /// Return an instance to a registered EventPublisher.
+ static EventPublisherRef getEventPublisher(EventPublisherID& pub);
+
+ /// Return an instance to a registered EventSubscriber.
+ static EventSubscriberRef getEventSubscriber(EventSubscriberID& pub);
+
+ public:
+ /// The dispatched event thread's entrypoint (if needed).
+ static Status run(EventPublisherID& type_id);
+
+ /// An initializer's entrypoint for spawning all event type run loops.
+ static void delay();
+
+ public:
+ /// If a static EventPublisher callback wants to fire
+ template <typename PUB>
+ static void fire(const EventContextRef& ec) {
+ auto event_pub = getEventPublisher(BaseEventPublisher::getType<PUB>());
+ event_pub->fire(ec);
+ }
+
+ /**
+ * @brief End all EventPublisher run loops and call their `tearDown` methods.
+ *
+ * End is NOT the same as deregistration.
+ *
+ * @param should_end Reset the "is ending" state if False.
*/
- static QueryData genTable();
+ static void end(bool should_end = true);
+
+ private:
+ /// An EventFactory will exist for the lifetime of the application.
+ EventFactory() {}
+ EventFactory(EventFactory const&);
+ void operator=(EventFactory const&);
+
+ private:
+ /// Set of registered EventPublisher instances.
+ std::map<EventPublisherID, EventPublisherRef> event_pubs_;
+
+ /// Set of instanciated EventSubscriber subscriptions.
+ std::map<EventSubscriberID, EventSubscriberRef> event_subs_;
+
+ /// Set of running EventPublisher run loop threads.
+ std::vector<std::shared_ptr<boost::thread> > threads_;
+};
+class EventSubscriberCore {
protected:
/**
* @brief Store parsed event data from an EventCallback in a backing store.
*/
virtual QueryData get(EventTime start, EventTime stop);
+ private:
/*
* @brief When `get`ting event results, return EventID%s from time indexes.
*
*/
std::vector<EventRecord> getRecords(const std::vector<std::string>& indexes);
- private:
/**
* @brief Get a unique storage-related EventID.
*
*
* @return Were the indexes recorded.
*/
- Status recordEvent(EventID eid, EventTime time);
+ Status recordEvent(EventID& eid, EventTime time);
- protected:
+ public:
/**
* @brief A single instance requirement for static callback facilities.
*
* EventPublisher instances will have run `setUp` and initialized their run
* loops.
*/
- EventSubscriber() {
+ EventSubscriberCore() {
expire_events_ = true;
expire_time_ = 0;
}
- virtual ~EventSubscriber() {}
+ ~EventSubscriberCore() {}
+ /**
+ * @brief Suggested entrypoint for table generation.
+ *
+ * The EventSubscriber is a convention that removes a lot of boilerplate event
+ * subscriptioning and acting. The `genTable` static entrypoint is the
+ * suggested method for table specs.
+ *
+ * @return The query-time table data, retrieved from a backing store.
+ */
+ virtual QueryData genTable(tables::QueryContext& context)
+ __attribute__((used)) {
+ return get(0, 0);
+ }
+
+ /// The string name identifying this EventSubscriber.
+ virtual EventSubscriberID name() { return "subscriber"; }
+
+ protected:
/// Backing storage indexing namespace definition methods.
EventPublisherID dbNamespace() { return type() + "." + name(); }
+
/// The string EventPublisher identifying this EventSubscriber.
- virtual EventPublisherID type() const = 0;
- /// The string name identifying this EventSubscriber.
- virtual EventPublisherID name() const = 0;
+ virtual EventPublisherID type() = 0;
+
/// Disable event expiration for this subscriber.
void doNotExpire() { expire_events_ = false; }
private:
FRIEND_TEST(EventsDatabaseTests, test_event_module_id);
- FRIEND_TEST(EventsDatabaseTests, test_unique_event_module_id);
FRIEND_TEST(EventsDatabaseTests, test_record_indexing);
FRIEND_TEST(EventsDatabaseTests, test_record_range);
FRIEND_TEST(EventsDatabaseTests, test_record_expiration);
};
/**
- * @brief A factory for associating event generators to EventPublisherID%s.
+ * @brief An interface binding Subscriptions, event response, and table
+ *generation.
*
- * This factory both registers new event types and the subscriptions that use
- * them. An EventPublisher is also a factory, the single event factory arbitates
- * Subscription creatating and management for each associated EventPublisher.
+ * Use the EventSubscriber interface when adding event subscriptions and
+ * defining callin functions. The EventCallback is usually a member function
+ * for an EventSubscriber. The EventSubscriber interface includes a very
+ * important `add` method that abstracts the needed event to backing store
+ * interaction.
*
- * Since event types may be plugins, they are created using the factory.
- * Since subscriptions may be configured/disabled they are also factory-managed.
+ * Storing event data in the backing store must match a table spec for queries.
+ * Small overheads exist that help query-time indexing and lookups.
*/
-class EventFactory {
- public:
- /// Access to the EventFactory instance.
- static EventFactory& getInstance();
-
- /**
- * @brief Add an EventPublisher to the factory.
- *
- * The registration is mostly abstracted using osquery's registery.
- */
- template <typename T>
- static Status registerEventPublisher() {
- auto event_pub = std::make_shared<T>();
- return EventFactory::registerEventPublisher(event_pub);
- }
-
- /**
- * @brief Add an EventPublisher to the factory.
- *
- * The registration is mostly abstracted using osquery's registery.
- *
- * @param event_pub If for some reason the caller needs access to the
- * EventPublisher instance they can register-by-instance.
- *
- * Access to the EventPublisher instance is not discouraged, but using the
- * EventFactory `getEventPublisher` accessor is encouraged.
- */
- static Status registerEventPublisher(const EventPublisherRef event_pub);
-
- /**
- * @brief Add an EventSubscriber to the factory.
- *
- * The registration is mostly abstracted using osquery's registery.
- */
- template <typename T>
- static Status registerEventSubscriber() {
- auto event_module = T::getInstance();
- return EventFactory::registerEventSubscriber(event_module);
- }
-
- /**
- * @brief Add an EventSubscriber to the factory.
- *
- * The registration is mostly abstracted using osquery's registery.
- *
- * @param event_module If the caller must access the EventSubscriber instance
- * control may be passed to the registry.
- *
- * Access to the EventSubscriber instance outside of the within-instance
- * table generation method and set of EventCallback%s is discouraged.
- */
- static Status registerEventSubscriber(const EventSubscriberRef event_module);
+template <class PUB>
+class EventSubscriber: public EventSubscriberCore {
+ protected:
+ typedef typename PUB::SCRef SCRef;
+ typedef typename PUB::ECRef ECRef;
+ public:
+ /// Called after EventPublisher `setUp`. Add all Subscription%s here.
/**
- * @brief Add a SubscriptionContext and EventCallback Subscription to an
- *EventPublisher.
- *
- * Create a Subscription from a given SubscriptionContext and EventCallback
- * and add that Subscription to the EventPublisher assosicated identiter.
- *
- * @param type_id The string for an EventPublisher receiving the Subscription.
- * @param mc A SubscriptionContext related to the EventPublisher.
- * @param cb When the EventPublisher fires an event the SubscriptionContext
- * will be evaluated, if the event matches optional specifics in the context
- * this callback function will be called. It should belong to an
- * EventSubscription.
+ * @brief Add Subscription%s to the EventPublisher this module will act on.
*
- * @return Was the SubscriptionContext appropriate for the EventPublisher.
+ * When the EventSubscriber%'s `init` method is called you are assured the
+ * EventPublisher has `setUp` and is ready to subscription for events.
*/
- static Status addSubscription(EventPublisherID type_id,
- const SubscriptionContextRef mc,
- EventCallback cb = 0);
-
- /// Add a Subscription using a caller Subscription instance.
- static Status addSubscription(EventPublisherID type_id,
- const SubscriptionRef subscription);
-
- /// Add a Subscription by templating the EventPublisher, using a
- /// SubscriptionContext.
- template <typename T>
- static Status addSubscription(const SubscriptionContextRef mc,
- EventCallback cb = 0) {
- return addSubscription(EventPublisher::type<T>(), mc, cb);
- }
-
- /// Add a Subscription by templating the EventPublisher, using a Subscription
- /// instance.
- template <typename T>
- static Status addSubscription(const SubscriptionRef subscription) {
- return addSubscription(EventPublisher::type<T>(), subscription);
- }
-
- /// Get the total number of Subscription%s across ALL EventPublisher%s.
- static size_t numSubscriptions(EventPublisherID type_id);
+ virtual void init() {}
- /// Get the number of EventPublishers.
- static size_t numEventPublishers() {
- return EventFactory::getInstance().event_pubs_.size();
- }
+ /// Helper function to call the publisher's templated subscription generator.
+ SCRef createSubscriptionContext() { return PUB::createSubscriptionContext(); }
/**
- * @brief Halt the EventPublisher run loop and call its `tearDown`.
- *
- * Any EventSubscriber%s with Subscription%s for this EventPublisher will
- * become useless. osquery instanciators MUST deregister events.
- * EventPublisher%s assume they can hook/trampoline, which requires cleanup.
- *
- * @param event_pub The string label for the EventPublisher.
+ * @brief Bind a registered EventSubscriber member function to a Subscription.
*
- * @return Did the EventPublisher deregister cleanly.
+ * @param entry A templated EventSubscriber member function.
+ * @param sc The subscription context.
*/
- static Status deregisterEventPublisher(const EventPublisherRef event_pub);
-
- /// Deregister an EventPublisher by EventPublisherID.
- static Status deregisterEventPublisher(EventPublisherID type_id);
-
- /// Deregister all EventPublisher%s.
- static Status deregisterEventPublishers();
-
- /// Return an instance to a registered EventPublisher.
- static EventPublisherRef getEventPublisher(EventPublisherID);
-
- public:
- /// The dispatched event thread's entrypoint (if needed).
- static Status run(EventPublisherID type_id);
-
- /// An initializer's entrypoint for spawning all event type run loops.
- static void delay();
-
- public:
- /// If a static EventPublisher callback wants to fire
- template <typename T>
- static void fire(const EventContextRef ec) {
- auto event_pub = getEventPublisher(EventPublisher::type<T>());
- event_pub->fire(ec);
+ template <class T, typename C>
+ void subscribe(Status (T::*entry)(const std::shared_ptr<C>&),
+ const SubscriptionContextRef& sc) {
+ // Up-cast the CRTP-style EventSubscriber to the caller.
+ auto self = dynamic_cast<T*>(this);
+ // Down-cast the pointer to the member function.
+ auto base_entry =
+ reinterpret_cast<Status (T::*)(const EventContextRef&)>(entry);
+ // Create a callable to the member function using the instance of the
+ // EventSubscriber and a single parameter placeholder (the EventContext).
+ auto cb = std::bind(base_entry, self, _1);
+ // Add a subscription using the callable and SubscriptionContext.
+ EventFactory::addSubscription(type(), sc, cb);
}
- /**
- * @brief End all EventPublisher run loops and call their `tearDown` methods.
- *
- * End is NOT the same as deregistration.
- *
- * @param should_end Reset the "is ending" state if False.
- */
- static void end(bool should_end = true);
+ /// Helper EventPublisher string type accessor.
+ EventPublisherID type() { return BaseEventPublisher::getType<PUB>(); }
private:
- /// An EventFactory will exist for the lifetime of the application.
- EventFactory() { ending_ = false; }
- EventFactory(EventFactory const&);
- void operator=(EventFactory const&);
-
- private:
- /// Set ending to True to cause event type run loops to finish.
- bool ending_;
-
- /// Set of registered EventPublisher instances.
- EventPublisherMap event_pubs_;
-
- /// Set of running EventPublisher run loop threads.
- std::vector<std::shared_ptr<boost::thread> > threads_;
-
- /// Set of instanciated EventSubscriber Subscription sets (with callbacks and
- /// state).
- std::vector<EventSubscriberRef> event_modules_;
+ FRIEND_TEST(EventsTests, test_event_sub);
+ FRIEND_TEST(EventsTests, test_event_sub_subscribe);
+ FRIEND_TEST(EventsTests, test_event_sub_context);
};
}
/// Expose a Plugin-like Registry for EventPublisher instances.
DECLARE_REGISTRY(EventPublishers, std::string, EventPublisherRef)
#define REGISTERED_EVENTPUBLISHERS REGISTRY(EventPublishers)
-#define REGISTER_EVENTPUBLISHER(decorator) \
- REGISTER(EventPublishers, #decorator, std::make_shared<decorator>())
+#define REGISTER_EVENTPUBLISHER(PUB) \
+ REGISTER(EventPublishers, #PUB, EventFactory::createEventPublisher<PUB>());
/**
* @brief Expose a Plugin-link Registry for EventSubscriber instances.
*/
DECLARE_REGISTRY(EventSubscribers, std::string, EventSubscriberRef)
#define REGISTERED_EVENTSUBSCRIBERS REGISTRY(EventSubscribers)
-#define REGISTER_EVENTSUBSCRIBER(decorator) \
- REGISTER(EventSubscribers, #decorator, decorator::getInstance())
+#define REGISTER_EVENTSUBSCRIBER(SUB) \
+ REGISTER(EventSubscribers, #SUB, EventFactory::createEventSubscriber<SUB>());
namespace osquery {
namespace registries {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
* @return status of iteration, failure if the process path did not exist.
*/
Status procDescriptors(const std::string& process,
- std::vector<std::string>& descriptors);
+ std::map<std::string, std::string>& descriptors);
/**
* @brief Read a descriptor's virtual path.
Status procReadDescriptor(const std::string& process,
const std::string& descriptor,
std::string& result);
+
+/**
+ * @brief Read bytes from Linux's raw memory.
+ *
+ * Most Linux kernels include a device node /dev/mem that allows privileged
+ * users to map or seek/read pages of physical memory.
+ * osquery discourages the use of physical memory reads for security and
+ * performance reasons and must first try safer methods for data parsing
+ * such as /sys and /proc.
+ *
+ * A platform user may disable physical memory reads:
+ * --disable_memory=true
+ * This flag/option will cause readRawMemory to forcefully fail.
+ *
+ * @param base The absolute memory address to read from. This does not need
+ * to be page aligned, readRawMem will take care of alignment and only
+ * return the requested start address and size.
+ * @param length The length of the buffer with a max of 0x10000.
+ * @param buffer The output buffer, caller is responsible for resources if
+ * readRawMem returns success.
+ * @return status The status of the read.
+ */
+Status readRawMem(size_t base, size_t length, void** buffer);
+
#endif
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
namespace osquery {
-/// Value, Description.
-typedef std::pair<std::string, std::string> FlagDetail;
+/// Type, Value, Description.
+typedef std::tuple<std::string, std::string, std::string> FlagDetail;
/**
* @brief A small tracking wrapper for options, binary flags.
* flag data requires the accessor wrapper.
*
* @param name The 'name' or the options switch data.
+ * @param type The lexical type of the flag.
* @param value The default value for this flag.
* @param desc The description printed to the screen during help.
* @param shell_only Only print flag help when using `OSQUERY_TOOL_SHELL`.
* @return A mostly needless flag instance.
*/
static Flag& get(const std::string& name = "",
+ const std::string& type = "",
const std::string& value = "",
const std::string& desc = "",
bool shell_only = false);
* @brief Wrapper by the Flag::get.
*
* @param name The 'name' or the options switch data.
+ * @parma type The lexical type of the flag.
* @param value The default value for this flag.
* @param desc The description printed to the screen during help.
* @param shell_only Restrict this flag to the shell help output.
*/
void add(const std::string& name,
+ const std::string& type,
const std::string& value,
const std::string& desc,
bool shell_only);
*
* @param name the flag name.
* @param value output parameter filled with the flag value on success.
- * @return status of the flag existed.
+ * @return status of the flag did exist.
*/
static Status getDefaultValue(const std::string& name, std::string& value);
* @return if the value was updated.
*/
static Status updateValue(const std::string& name, const std::string& value);
+
+ /*
+ * @brief Get the value of an osquery flag.
+ *
+ * @param name the flag name.
+ */
+ std::string getValue(const std::string& name);
+
/*
* @brief Print help-style output to stdout for a given flag set.
*
#define DEFINE_osquery_flag(type, name, value, desc) \
DEFINE_##type(name, value, desc); \
namespace flag_##name { \
- Flag flag = Flag::get(#name, #value, desc); \
+ Flag flag = Flag::get(#name, #type, #value, desc); \
}
/*
#define DEFINE_shell_flag(type, name, value, desc) \
DEFINE_##type(name, value, desc); \
namespace flag_##name { \
- Flag flag = Flag::get(#name, #value, desc, true); \
+ Flag flag = Flag::get(#name, #type, #value, desc, true); \
}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <string>
+
+namespace osquery {
+
+/**
+ * @brief The supported hashing algorithms in osquery
+ *
+ * These are usually used as a constructor argument to osquery::Hash
+ */
+enum HashType {
+ HASH_TYPE_MD5 = 2,
+ HASH_TYPE_SHA1 = 4,
+ HASH_TYPE_SHA256 = 8,
+};
+
+/**
+ * @brief Hash is a general utility class for hashing content
+ *
+ * @code{.cpp}
+ * Hash my_hash(HASH_TYPE_SHA256);
+ * my_hash.update(my_buffer, my_buffer_size);
+ * std::cout << my_hash.digest();
+ * @endcode
+ *
+ */
+class Hash {
+ public:
+ /**
+ * @brief Hash constructor
+ *
+ * The hash class should be initialized with one of osquery::HashType as a
+ * constructor argument.
+ *
+ * @param algorithm The hashing algorithm which will be used to compute the
+ * hash
+ */
+ explicit Hash(HashType algorithm);
+
+ /**
+ * @brief Hash destructor
+ */
+ ~Hash();
+
+ /**
+ * @brief Update the internal context buffer with additional content
+ *
+ * This method allows you to chunk up large content so that it doesn't all
+ * have to be loaded into memory at the same time
+ *
+ * @param buffer The buffer to be hashed
+ * @param size The size of the buffer to be hashed
+ */
+ void update(const void* buffer, size_t size);
+
+ /**
+ * @brief Compute the final hash and return it's result
+ *
+ * @return The final hash value
+ */
+ std::string digest();
+
+ private:
+ /**
+ * @brief Private default constructor
+ *
+ * The osquery::Hash class should only ever be instantiated with a HashType
+ */
+ Hash(){};
+
+ private:
+ /// The hashing algorithm which is used to compute the hash
+ HashType algorithm_;
+
+ /// The buffer used to maintain the context and state of the hashing
+ /// operations
+ void* ctx_;
+
+ /// The length of the hash to be returned
+ size_t length_;
+};
+
+/**
+ * @brief Compute a hash digest from an already allocated buffer.
+ *
+ * @param hash_type The osquery-supported hash algorithm.
+ * @param buffer A caller-controlled buffer.
+ * @param size The length of buffer in bytes.
+ * @return A string (hex) representation of the hash digest.
+ */
+std::string hashFromBuffer(HashType hash_type, const void* buffer, size_t size);
+
+/**
+ * @brief Compute a hash digest from the file content at a path.
+ *
+ *
+ * @param hash_type The osquery-supported hash algorithm.
+ * @param path Filesystem path, the hash target.
+ * @return A string (hex) representation of the hash digest.
+ */
+std::string hashFromFile(HashType hash_type, const std::string& path);
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <glog/logging.h>
#include <osquery/status.h>
-#include <osquery/database.h>
+#include <osquery/scheduler.h>
namespace osquery {
* @return an instance of osquery::Status, indicating the success or failure
* of the operation.
*/
-osquery::Status logString(const std::string& s);
+Status logString(const std::string& s);
/**
* @brief Log a string using a specific logger receiver.
* @return an instance of osquery::Status, indicating the success or failure
* of the operation.
*/
-osquery::Status logString(const std::string& s, const std::string& receiver);
+Status logString(const std::string& s, const std::string& receiver);
/**
* @brief Directly log results of scheduled queries to the default receiver
* @return an instance of osquery::Status, indicating the success or failure
* of the operation.
*/
-osquery::Status logScheduledQueryLogItem(
- const osquery::ScheduledQueryLogItem& item);
+Status logScheduledQueryLogItem(const ScheduledQueryLogItem& item);
/**
* @brief Directly log results of scheduled queries to a specified receiver
* @return an instance of osquery::Status, indicating the success or failure
* of the operation.
*/
-osquery::Status logScheduledQueryLogItem(
- const osquery::ScheduledQueryLogItem& item, const std::string& receiver);
+Status logScheduledQueryLogItem(const ScheduledQueryLogItem& item,
+ const std::string& receiver);
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <unordered_map>
#include <utility>
-#include <glog/logging.h>
+#include <osquery/database/results.h>
+#include <osquery/logger.h>
#include "osquery/registry/init_registry.h"
#include "osquery/registry/singleton.h"
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
+#include <osquery/database/results.h>
+
namespace osquery {
/**
+ * @brief represents the relevant parameters of a scheduled query.
+ *
+ * Within the context of osqueryd, a scheduled query may have many relevant
+ * attributes. Those attributes are represented in this data structure.
+ */
+struct OsqueryScheduledQuery {
+ /// name represents the "name" of a query.
+ std::string name;
+
+ /// query represents the actual SQL query.
+ std::string query;
+
+ /// interval represents how often the query should be executed, in minutes.
+ int interval;
+
+ /// equals operator
+ bool operator==(const OsqueryScheduledQuery& comp) const {
+ return (comp.name == name) && (comp.query == query) &&
+ (comp.interval == interval);
+ }
+
+ /// not equals operator
+ bool operator!=(const OsqueryScheduledQuery& comp) const {
+ return !(*this == comp);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// ScheduledQueryLogItem
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief A data structure which represents data to log in the event of an
+ * operating system state change
+ *
+ * When a scheduled query yields new results, we need to log that information
+ * to our upstream logging receiver. The data that needs to be logged is the
+ * entire DiffResults set as well as some additional metadata.
+ */
+struct ScheduledQueryLogItem {
+ /// The data which was changed as a result of the scheduled query
+ DiffResults diffResults;
+
+ /// The name of the scheduled query
+ std::string name;
+
+ /// The identifier (hostname, or uuid) of the host on which the query was
+ /// executed
+ std::string hostIdentifier;
+
+ /// The time that the query was executed, in unix time
+ int unixTime;
+
+ /// The time that the query was executed, in ASCII
+ std::string calendarTime;
+
+ /// equals operator
+ bool operator==(const ScheduledQueryLogItem& comp) const {
+ return (comp.diffResults == diffResults) && (comp.name == name);
+ }
+
+ /// not equals operator
+ bool operator!=(const ScheduledQueryLogItem& comp) const {
+ return !(*this == comp);
+ }
+};
+
+/**
+ * @brief Serialize a ScheduledQueryLogItem object into a property tree
+ *
+ * @param i the ScheduledQueryLogItem to serialize
+ * @param tree a reference to a property tree which, if all operations are
+ * completed successfully, the contents of ScheduledQueryLogItem will be
+ * serialized into
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation
+ */
+Status serializeScheduledQueryLogItem(const ScheduledQueryLogItem& i,
+ boost::property_tree::ptree& tree);
+
+/**
+ * @brief Serialize a ScheduledQueryLogItem object into a JSON string
+ *
+ * @param i the ScheduledQueryLogItem to serialize
+ * @param json a reference to a string which, if all operations are completed
+ * successfully, the contents of ScheduledQueryLogItem will be serialized into
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation
+ */
+Status serializeScheduledQueryLogItemJSON(const ScheduledQueryLogItem& i,
+ std::string& json);
+
+/**
+ * @brief Serialize a ScheduledQueryLogItem object into a property tree
+ * of events, a list of actions.
+ *
+ * @param item the ScheduledQueryLogItem to serialize
+ * @param tree a reference to a property tree which, if all operations are
+ * completed successfully, the contents of ScheduledQueryLogItem will be
+ * serialized into
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation
+ */
+Status serializeScheduledQueryLogItemAsEvents(
+ const ScheduledQueryLogItem& item, boost::property_tree::ptree& tree);
+
+/**
+ * @brief Serialize a ScheduledQueryLogItem object into a JSON string of events,
+ * a list of actions.
+ *
+ * @param i the ScheduledQueryLogItem to serialize
+ * @param json a reference to a string which, if all operations are completed
+ * successfully, the contents of ScheduledQueryLogItem will be serialized into
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation
+ */
+Status serializeScheduledQueryLogItemAsEventsJSON(
+ const ScheduledQueryLogItem& i, std::string& json);
+
+/**
* @brief Launch the scheduler.
*
* osquery comes with a scheduler, which schedules a variety of things. This
* @endcode
*/
void initializeScheduler();
+
+/**
+ * @brief Calculate a splayed integer based on a variable splay percentage
+ *
+ * The value of splayPercent must be between 1 and 100. If it's not, the
+ * value of original will be returned.
+ *
+ * @param original The original value to be modified
+ * @param splayPercent The percent in which to splay the original value by
+ *
+ * @return The modified version of original
+ */
+int splayValue(int original, int splayPercent);
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <osquery/database/results.h>
#include <osquery/status.h>
+#ifndef FRIEND_TEST
+#define FRIEND_TEST(test_case_name, test_name) \
+ friend class test_case_name##_##test_name##_Test
+#endif
+
namespace osquery {
namespace tables {
/// Cast an SQLite affinity type to the literal type.
#define AS_LITERAL(literal, value) boost::lexical_cast<literal>(value)
+/// Helper alias for TablePlugin names.
+typedef const std::string TableName;
+typedef const std::vector<std::pair<std::string, std::string> > TableColumns;
+typedef std::map<std::string, std::vector<std::string> > TableData;
+
/**
* @brief A ConstraintOperator is applied in an query predicate.
*
/// Construct a Constraint with the most-basic information, the operator.
Constraint(unsigned char _op) { op = _op; }
+
+ // A constraint list in a context knows only the operator at creation.
+ Constraint(unsigned char _op, const std::string& _expr) {
+ op = _op;
+ expr = _expr;
+ }
};
/**
* A constraint list supports all AS_LITERAL types, and all ConstraintOperators.
*/
struct ConstraintList {
- /// List of constraint operator/expressions.
- std::vector<struct Constraint> constraints;
/// The SQLite affinity type.
std::string affinity;
/**
* @brief Check if an expression matches the query constraints.
*
- * @param expr a TEXT representation of the column literal type to check.
+ * Evaluate ALL constraints in this ConstraintList against the string
+ * expression. The affinity of the constrait will be used as the affinite
+ * and lexical type of the expression and set of constraint expressions.
+ *
+ * @param expr a SQL type expression of the column literal type to check.
* @return If the expression matched all constraints.
*/
bool matches(const std::string& expr);
+ /**
+ * @brief Check if an expression matches the query constraints.
+ *
+ * `matches` also supports the set of SQL affinite types.
+ * The expression expr will be evaluated as a string and compared using
+ * the affinity of the constraint.
+ *
+ * @param expr a SQL type expression of the column literal type to check.
+ * @return If the expression matched all constraints.
+ */
template <typename T>
bool matches(const T& expr) {
- return literal_matches<T>(expr);
+ return matches(TEXT(expr));
}
/**
- * @brief If there is a constraint on this column.
+ * @brief Check and return if there are any 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.
+ *
+ * @return true if any constraint exists.
*/
- bool exists() { return (constraints.size() > 0); }
- bool existsAndMatches(const std::string& expr) {
+ bool exists() { return (constraints_.size() > 0); }
+
+ /**
+ * @brief Check if a constrait exist AND matches the type expression.
+ *
+ * See ConstraintList::exists and ConstraintList::matches.
+ *
+ * @param expr The expression to match.
+ * @return true if any constraint exists AND matches the type expression.
+ */
+ template <typename T>
+ bool existsAndMatches(const T& expr) {
return (exists() && matches(expr));
}
- bool notExistsOrMatches(const std::string& expr) {
+ /**
+ * @brief Check if a constraint is missing or matches a type expression.
+ *
+ * A ConstraintList is used in a ConstraintMap with a column name as the
+ * map index. Tables that act on required constraints can make decisions
+ * on missing constraints or a constraint match.
+ *
+ * @param expr The expression to match.
+ * @return true if constraint is missing or matches the type expression.
+ */
+ template <typename T>
+ bool notExistsOrMatches(const T& expr) {
return (!exists() || matches(expr));
}
- template <typename T>
- bool existsAndMatches(const T& expr);
-
- template <typename T>
- bool notExistsOrMatches(const T& expr);
-
/**
- * @brief Helper templated function for ConstraintList::matches
+ * @brief Helper templated function for ConstraintList::matches.
*/
template <typename T>
bool literal_matches(const T& base_expr);
* @param constraint a new operator/expression to constrain.
*/
void add(const struct Constraint& constraint) {
- constraints.push_back(constraint);
+ constraints_.push_back(constraint);
}
+
+ ConstraintList() { affinity = "TEXT"; }
+
+ private:
+ /// List of constraint operator/expressions.
+ std::vector<struct Constraint> constraints_;
+
+ private:
+ FRIEND_TEST(TablesTests, test_constraint_list);
};
/// Pass a constraint map to the query request.
typedef struct QueryContext QueryContext;
typedef struct Constraint Constraint;
+
+/**
+ * @brief The TablePlugin defines the name, types, and column information.
+ *
+ * To attach a virtual table create a TablePlugin subclass and register the
+ * virtual table name as the plugin ID. osquery will enumerate all registered
+ * TablePlugins and attempt to attach them to SQLite at instanciation.
+ */
+class TablePlugin {
+ public:
+ TableName name;
+ TableColumns columns;
+ /// Helper method to generate the virtual table CREATE statement.
+ std::string statement(TableName name, TableColumns columns);
+
+ public:
+ /// Part of the query state, number of rows generated.
+ int n;
+ /// Part of the query state, column data returned from a query.
+ TableData data;
+ /// Part of the query state, parsed set of query predicate constraints.
+ ConstraintSet constraints;
+
+ public:
+ virtual int attachVtable(sqlite3 *db) { return -1; }
+ virtual ~TablePlugin(){};
+
+ protected:
+ TablePlugin() { n = 0; };
+};
+
+typedef std::shared_ptr<TablePlugin> TablePluginRef;
}
}
boost_system
boost_thread
boost_filesystem
+ crypto # openssl
# shell deps
readline
# build-in tables deps
GROUP_EXECUTE
WORLD_READ
WORLD_EXECUTE)
-
ADD_OSQUERY_LIBRARY(osquery_config config.cpp
- plugins/filesystem.cpp
- plugins/glog.cpp)
+ plugins/filesystem.cpp)
ADD_OSQUERY_TEST(osquery_config_tests config_tests.cpp)
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <algorithm>
-#include <future>
-#include <random>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <mutex>
#include <sstream>
-#include <string>
-#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/thread/shared_mutex.hpp>
-#include <glog/logging.h>
-
#include <osquery/config.h>
#include <osquery/config/plugin.h>
#include <osquery/flags.h>
-#include <osquery/status.h>
-
-using osquery::Status;
+#include <osquery/hash.h>
+#include <osquery/logger.h>
namespace pt = boost::property_tree;
"filesystem",
"Config type (plugin).");
-DEFINE_osquery_flag(int32,
- schedule_splay_percent,
- 10,
- "Percent to splay config times.");
-
-boost::shared_mutex rw_lock;
+static boost::shared_mutex rw_lock;
std::shared_ptr<Config> Config::getInstance() {
static std::shared_ptr<Config> config = std::shared_ptr<Config>(new Config());
return config;
}
-Config::Config() {
+Status Config::load() {
boost::unique_lock<boost::shared_mutex> lock(rw_lock);
OsqueryConfig conf;
+
auto s = Config::genConfig(conf);
if (!s.ok()) {
- LOG(ERROR) << "error retrieving config: " << s.toString();
- return;
+ return Status(1, "Cannot generate config");
}
// Override default arguments with flag options from config.
}
}
- // Iterate over scheduled queryies and add a splay to each.
- for (auto& q : conf.scheduledQueries) {
- auto old_interval = q.interval;
- auto new_interval = splayValue(old_interval, FLAGS_schedule_splay_percent);
- LOG(INFO) << "Changing the interval for " << q.name << " from "
- << old_interval << " to " << new_interval;
- q.interval = new_interval;
- }
cfg_ = conf;
+ return Status(0, "OK");
}
-Status Config::genConfig(OsqueryConfig& conf) {
- std::stringstream json;
- pt::ptree tree;
-
+Status Config::genConfig(std::string& conf) {
if (REGISTERED_CONFIG_PLUGINS.find(FLAGS_config_retriever) ==
REGISTERED_CONFIG_PLUGINS.end()) {
LOG(ERROR) << "Config retriever " << FLAGS_config_retriever << " not found";
return Status(1, "Config retriever not found");
}
- auto config_data =
- REGISTERED_CONFIG_PLUGINS.at(FLAGS_config_retriever)->genConfig();
- if (!config_data.first.ok()) {
- return config_data.first;
+
+ try {
+ auto config_data =
+ REGISTERED_CONFIG_PLUGINS.at(FLAGS_config_retriever)->genConfig();
+ if (!config_data.first.ok()) {
+ return config_data.first;
+ }
+ conf = config_data.second;
+ } catch (std::exception& e) {
+ LOG(ERROR) << "Could not load ConfigPlugin " << FLAGS_config_retriever
+ << ": " << e.what();
+ return Status(1, "Could not load config plugin");
+ }
+
+ return Status(0, "OK");
+}
+
+Status Config::genConfig(OsqueryConfig& conf) {
+ std::string config_string;
+ auto s = genConfig(config_string);
+ if (!s.ok()) {
+ return s;
}
- json << config_data.second;
- pt::read_json(json, tree);
+ std::stringstream json;
+ pt::ptree tree;
try {
+ json << config_string;
+ pt::read_json(json, tree);
+
// Parse each scheduled query from the config.
for (const pt::ptree::value_type& v : tree.get_child("scheduledQueries")) {
OsqueryScheduledQuery q;
return cfg_.scheduledQueries;
}
-int Config::splayValue(int original, int splayPercent) {
- if (splayPercent <= 0 || splayPercent > 100) {
- return original;
+Status Config::getMD5(std::string& hash_string) {
+ std::string config_string;
+ auto s = genConfig(config_string);
+ if (!s.ok()) {
+ return s;
}
- 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;
+ hash_string = osquery::hashFromBuffer(
+ HASH_TYPE_MD5, (void*)config_string.c_str(), config_string.length());
- if (max_value == min_value) {
- return max_value;
- }
+ return Status(0, "OK");
+}
- std::default_random_engine generator;
- std::uniform_int_distribution<int> distribution(min_value, max_value);
- return distribution(generator);
+Status Config::checkConfig() {
+ OsqueryConfig c;
+ return genConfig(c);
}
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <osquery/core.h>
#include <osquery/config.h>
#include <osquery/config/plugin.h>
-#include <osquery/status.h>
+#include <osquery/core.h>
+#include <osquery/flags.h>
#include <osquery/registry.h>
-using osquery::Status;
+#include "osquery/core/test_util.h"
namespace osquery {
+// The config_path flag is defined in the filesystem config plugin.
+DECLARE_string(config_path);
+
class ConfigTests : public testing::Test {
public:
- ConfigTests() { osquery::InitRegistry::get().run(); }
+ ConfigTests() {
+ FLAGS_config_retriever = "filesystem";
+ FLAGS_config_path = kTestDataPath + "test.config";
+
+ osquery::InitRegistry::get().run();
+ auto c = Config::getInstance();
+ c->load();
+ }
};
TEST_F(ConfigTests, test_queries_execute) {
auto c = Config::getInstance();
- for (const auto& i : c->getScheduledQueries()) {
+ auto queries = c->getScheduledQueries();
+
+ EXPECT_EQ(queries.size(), 1);
+ for (const auto& i : queries) {
int err;
auto r = query(i.query, err);
EXPECT_EQ(err, 0);
-
- // At most query one shceduled query from the config.
- break;
}
}
EXPECT_EQ(p.first.toString(), "OK");
EXPECT_EQ(p.second, "foobar");
}
-
-TEST_F(ConfigTests, test_splay) {
- auto val1 = Config::splayValue(100, 10);
- EXPECT_GE(val1, 90);
- EXPECT_LE(val1, 110);
-
- auto val2 = Config::splayValue(100, 10);
- EXPECT_GE(val2, 90);
- EXPECT_LE(val2, 110);
-
- auto val3 = Config::splayValue(10, 0);
- EXPECT_EQ(val3, 10);
-
- auto val4 = Config::splayValue(100, 1);
- EXPECT_GE(val4, 99);
- EXPECT_LE(val4, 101);
-
- auto val5 = Config::splayValue(1, 10);
- EXPECT_EQ(val5, 1);
-}
}
int main(int argc, char* argv[]) {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <fstream>
#include <osquery/config/plugin.h>
#include <osquery/flags.h>
+#include <osquery/logger.h>
namespace fs = boost::filesystem;
using osquery::Status;
return std::make_pair(Status(1, "config file does not exist"), config);
}
+ VLOG(1) << "Filesystem ConfigPlugin reading: " << FLAGS_config_path;
std::ifstream config_stream(FLAGS_config_path);
config_stream.seekg(0, std::ios::end);
+++ /dev/null
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <glog/logging.h>
-
-#include <osquery/logger/plugin.h>
-
-namespace osquery {
-
-class GlogPlugin : public LoggerPlugin {
- public:
- Status logString(const std::string& message) {
- LOG(INFO) << message;
- return Status(0, "OK");
- }
-
- virtual ~GlogPlugin() {}
-};
-
-REGISTER_LOGGER_PLUGIN("glog", std::make_shared<osquery::GlogPlugin>());
-}
-ADD_OSQUERY_LIBRARY(osquery_core init_osquery.cpp
+ADD_OSQUERY_LIBRARY(osquery_core init.cpp
+ conversions.cpp
sql.cpp
sqlite_util.cpp
system.cpp
text.cpp
tables.cpp
virtual_table.cpp
- flags.cpp)
+ flags.cpp
+ hash.cpp)
+ADD_OSQUERY_TEST(osquery_hash_tests hash_tests.cpp)
ADD_OSQUERY_TEST(osquery_status_tests status_tests.cpp)
ADD_OSQUERY_TEST(osquery_sql_tests sql_tests.cpp)
ADD_OSQUERY_TEST(osquery_sqlite_util_tests sqlite_util_tests.cpp)
+ADD_OSQUERY_TEST(osquery_tables_tests tables_tests.cpp)
ADD_OSQUERY_TEST(osquery_test_util_tests test_util_tests.cpp)
ADD_OSQUERY_TEST(osquery_text_tests text_tests.cpp)
ADD_OSQUERY_TEST(osquery_conversions_tests conversions_tests.cpp)
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <sstream>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+
+#include "osquery/core/conversions.h"
+
+namespace bai = boost::archive::iterators;
+
+namespace osquery {
+
+typedef bai::binary_from_base64<const char*> base64_str;
+typedef bai::transform_width<base64_str, 8, 6> base64_dec;
+
+std::string base64Decode(const std::string& encoded) {
+ std::string is;
+ std::stringstream os;
+
+ is = encoded;
+ boost::replace_all(is, "\r\n", "");
+ boost::replace_all(is, "\n", "");
+ uint32_t size = is.size();
+
+ // Remove the padding characters
+ if (size && is[size - 1] == '=') {
+ --size;
+ if (size && is[size - 1] == '=') {
+ --size;
+ }
+ }
+
+ if (size == 0) {
+ return std::string();
+ }
+
+ std::copy(base64_dec(is.data()),
+ base64_dec(is.data() + size),
+ std::ostream_iterator<char>(os));
+
+ return os.str();
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/flags.h>
namespace osquery {
Flag& Flag::get(const std::string& name,
+ const std::string& type,
const std::string& value,
const std::string& desc,
bool shell_only) {
static Flag f;
if (name != "") {
- f.add(name, value, desc, shell_only);
+ f.add(name, type, value, desc, shell_only);
}
return f;
}
void Flag::add(const std::string& name,
+ const std::string& type,
const std::string& value,
const std::string& desc,
bool shell_only) {
+ auto escaped_value = value;
+ if (type == "string") {
+ escaped_value.erase(0, 1);
+ escaped_value.erase(escaped_value.end() - 1, escaped_value.end());
+ }
if (!shell_only) {
- flags_.insert(std::make_pair(name, std::make_pair(value, desc)));
+ flags_.insert(
+ std::make_pair(name, std::make_tuple(type, escaped_value, desc)));
} else {
- shell_flags_.insert(std::make_pair(name, std::make_pair(value, desc)));
+ shell_flags_.insert(
+ std::make_pair(name, std::make_tuple(type, escaped_value, desc)));
}
}
Status Flag::getDefaultValue(const std::string& name, std::string& value) {
if (Flag::get().flags().count(name)) {
- value = Flag::get().flags()[name].first;
+ value = std::get<1>(Flag::get().flags()[name]);
} else if (Flag::get().shellFlags().count(name)) {
- value = Flag::get().shellFlags()[name].first;
+ value = std::get<1>(Flag::get().shellFlags()[name]);
} else {
return Status(1, "Flag name not found.");
}
if (!getDefaultValue(name, default_value).ok()) {
return false;
}
-
return (default_value == current_value);
}
+std::string Flag::getValue(const std::string& name) {
+ std::string current_value;
+ __GFLAGS_NAMESPACE::GetCommandLineOption(name.c_str(), ¤t_value);
+ return current_value;
+}
+
Status Flag::updateValue(const std::string& name, const std::string& value) {
__GFLAGS_NAMESPACE::SetCommandLineOption(name.c_str(), value.c_str());
return Status(0, "OK");
void Flag::printFlags(const std::map<std::string, FlagDetail> flags) {
for (const auto& flag : flags) {
fprintf(stdout,
- " --%s, --%s=%s\n %s\n",
- flag.first.c_str(),
+ " --%s=%s\n %s\n",
flag.first.c_str(),
- flag.second.first.c_str(),
- flag.second.second.c_str());
+ std::get<1>(flag.second).c_str(),
+ std::get<2>(flag.second).c_str());
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <iomanip>
+#include <sstream>
+
+#include <osquery/hash.h>
+#include <osquery/logger.h>
+
+namespace osquery {
+
+#ifdef __APPLE__
+ #import <CommonCrypto/CommonDigest.h>
+ #define __HASH_API(name) CC_##name
+#else
+ #include <openssl/sha.h>
+ #include <openssl/md5.h>
+ #define __HASH_API(name) name
+
+ #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
+ #define SHA1_CTX SHA_CTX
+#endif
+
+#define HASH_CHUNK_SIZE 1024
+
+Hash::~Hash() {
+ if (ctx_ != nullptr) {
+ free(ctx_);
+ }
+}
+
+Hash::Hash(HashType algorithm) : algorithm_(algorithm) {
+ if (algorithm_ == HASH_TYPE_MD5) {
+ length_ = __HASH_API(MD5_DIGEST_LENGTH);
+ ctx_ = (__HASH_API(MD5_CTX)*)malloc(sizeof(__HASH_API(MD5_CTX)));
+ __HASH_API(MD5_Init)((__HASH_API(MD5_CTX)*)ctx_);
+ } else if (algorithm_ == HASH_TYPE_SHA1) {
+ length_ = __HASH_API(SHA1_DIGEST_LENGTH);
+ ctx_ = (__HASH_API(SHA1_CTX)*)malloc(sizeof(__HASH_API(SHA1_CTX)));
+ __HASH_API(SHA1_Init)((__HASH_API(SHA1_CTX)*)ctx_);
+ } else if (algorithm_ == HASH_TYPE_SHA256) {
+ length_ = __HASH_API(SHA256_DIGEST_LENGTH);
+ ctx_ = (__HASH_API(SHA256_CTX)*)malloc(sizeof(__HASH_API(SHA256_CTX)));
+ __HASH_API(SHA256_Init)((__HASH_API(SHA256_CTX)*)ctx_);
+ } else {
+ throw std::domain_error("Unknown hash function");
+ }
+}
+
+void Hash::update(const void* buffer, size_t size) {
+ if (algorithm_ == HASH_TYPE_MD5) {
+ __HASH_API(MD5_Update)((__HASH_API(MD5_CTX)*)ctx_, buffer, size);
+ } else if (algorithm_ == HASH_TYPE_SHA1) {
+ __HASH_API(SHA1_Update)((__HASH_API(SHA1_CTX)*)ctx_, buffer, size);
+ } else if (algorithm_ == HASH_TYPE_SHA256) {
+ __HASH_API(SHA256_Update)((__HASH_API(SHA256_CTX)*)ctx_, buffer, size);
+ }
+}
+
+std::string Hash::digest() {
+ unsigned char hash[length_];
+
+ if (algorithm_ == HASH_TYPE_MD5) {
+ __HASH_API(MD5_Final)(hash, (__HASH_API(MD5_CTX)*)ctx_);
+ } else if (algorithm_ == HASH_TYPE_SHA1) {
+ __HASH_API(SHA1_Final)(hash, (__HASH_API(SHA1_CTX)*)ctx_);
+ } else if (algorithm_ == HASH_TYPE_SHA256) {
+ __HASH_API(SHA256_Final)(hash, (__HASH_API(SHA256_CTX)*)ctx_);
+ }
+
+ // The hash value is only relevant as a hex digest.
+ std::stringstream digest;
+ for (int i = 0; i < length_; i++) {
+ digest << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
+ }
+
+ return digest.str();
+}
+
+std::string hashFromBuffer(HashType hash_type, const void* buffer, size_t size) {
+ Hash hash(hash_type);
+ hash.update(buffer, size);
+ return hash.digest();
+}
+
+std::string hashFromFile(HashType hash_type, const std::string& path) {
+ Hash hash(hash_type);
+
+ FILE* file = fopen(path.c_str(), "rb");
+ if (file == nullptr) {
+ VLOG(1) << "Cannot hash/open file " << path;
+ return "";
+ }
+
+ // Then call updates with read chunks.
+ size_t bytes_read = 0;
+ unsigned char buffer[HASH_CHUNK_SIZE];
+ while ((bytes_read = fread(buffer, 1, HASH_CHUNK_SIZE, file))) {
+ hash.update(buffer, bytes_read);
+ }
+
+ fclose(file);
+ return hash.digest();
+}
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <gtest/gtest.h>
+
+#include <osquery/hash.h>
+
+#include "osquery/core/test_util.h"
+
+namespace osquery {
+
+class HashTests : public testing::Test {};
+
+TEST_F(HashTests, test_algorithms) {
+ const unsigned char buffer[1] = {'0'};
+
+ auto digest = hashFromBuffer(HASH_TYPE_MD5, buffer, 1);
+ EXPECT_EQ(digest, "cfcd208495d565ef66e7dff9f98764da");
+
+ digest = hashFromBuffer(HASH_TYPE_SHA1, buffer, 1);
+ EXPECT_EQ(digest, "b6589fc6ab0dc82cf12099d1c2d40ab994e8410c");
+
+ digest = hashFromBuffer(HASH_TYPE_SHA256, buffer, 1);
+ EXPECT_EQ(digest,
+ "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9");
+}
+
+TEST_F(HashTests, test_update) {
+ const unsigned char buffer[1] = {'0'};
+
+ Hash hash(HASH_TYPE_MD5);
+ hash.update(buffer, 1);
+ hash.update(buffer, 1);
+ auto digest = hash.digest();
+ EXPECT_EQ(digest, "b4b147bc522828731f1a016bfa72c073");
+}
+
+TEST_F(HashTests, test_file_hashing) {
+ auto digest = hashFromFile(HASH_TYPE_MD5, kTestDataPath + "test_hashing.bin");
+ EXPECT_EQ(digest, "88ee11f2aa7903f34b8b8785d92208b1");
+}
+}
+
+int main(int argc, char* argv[]) {
+ testing::InitGoogleTest(&argc, argv);
+ osquery::initOsquery(argc, argv);
+ return RUN_ALL_TESTS();
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <glog/logging.h>
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <syslog.h>
+
+#include <osquery/config.h>
#include <osquery/core.h>
#include <osquery/flags.h>
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
#include <osquery/registry.h>
namespace osquery {
"/var/log/osquery/",
"Directory to store ERROR/INFO and results logging.");
-static const char* basename(const char* filename) {
- const char* sep = strrchr(filename, '/');
- return sep ? sep + 1 : filename;
+namespace fs = boost::filesystem;
+
+void printUsage(const std::string& binary, int tool) {
+ // Parse help options before gflags. Only display osquery-related options.
+ fprintf(stdout, "osquery " OSQUERY_VERSION ", %s\n", kDescription.c_str());
+ if (tool == OSQUERY_TOOL_SHELL) {
+ // The shell allows a caller to run a single SQL statement and exit.
+ fprintf(
+ stdout, "Usage: %s [OPTION]... [SQL STATEMENT]\n\n", binary.c_str());
+ } else {
+ fprintf(stdout, "Usage: %s [OPTION]...\n\n", binary.c_str());
+ }
+ fprintf(stdout,
+ "The following options control the osquery "
+ "daemon and shell.\n\n");
+
+ Flag::printFlags(Flag::get().flags());
+
+ if (tool == OSQUERY_TOOL_SHELL) {
+ // Print shell flags.
+ fprintf(stdout, "\nThe following options control the osquery shell.\n\n");
+ Flag::printFlags(Flag::get().shellFlags());
+ }
+
+ fprintf(stdout, "\n%s\n", kEpilog.c_str());
+}
+
+void announce(const std::string& basename) {
+ syslog(LOG_NOTICE, "osqueryd started [version=" OSQUERY_VERSION "]");
}
void initOsquery(int argc, char* argv[], int tool) {
- std::string binary(basename(argv[0]));
+ std::string binary(fs::path(std::string(argv[0])).filename().string());
std::string first_arg = (argc > 1) ? std::string(argv[1]) : "";
+ // osquery implements a custom help/usage output.
if ((first_arg == "--help" || first_arg == "-h" || first_arg == "-help") &&
tool != OSQUERY_TOOL_TEST) {
- // Parse help options before gflags. Only display osquery-related options.
- fprintf(stdout, "osquery " OSQUERY_VERSION ", %s\n", kDescription.c_str());
- if (tool == OSQUERY_TOOL_SHELL) {
- // The shell allows a caller to run a single SQL statement and exit.
- fprintf(
- stdout, "Usage: %s [OPTION]... [SQL STATEMENT]\n\n", binary.c_str());
- } else {
- fprintf(stdout, "Usage: %s [OPTION]...\n\n", binary.c_str());
- }
- fprintf(stdout,
- "The following options control the osquery "
- "daemon and shell.\n\n");
-
- Flag::printFlags(Flag::get().flags());
-
- if (tool == OSQUERY_TOOL_SHELL) {
- // Print shell flags.
- fprintf(stdout, "\nThe following options control the osquery shell.\n\n");
- Flag::printFlags(Flag::get().shellFlags());
- }
-
- fprintf(stdout, "\n%s\n", kEpilog.c_str());
-
+ printUsage(binary, tool);
::exit(0);
}
+ // Print the version to SYSLOG.
+ if (tool == OSQUERY_TOOL_DAEMON) {
+ announce(binary);
+ }
+
FLAGS_alsologtostderr = true;
FLAGS_logbufsecs = 0; // flush the log buffer immediately
FLAGS_stop_logging_if_full_disk = true;
}
google::InitGoogleLogging(argv[0]);
+ VLOG(1) << "osquery starting [version=" OSQUERY_VERSION "]";
osquery::InitRegistry::get().run();
+
+// Once command line arguments are parsed load the osquery config.
+#ifdef OSQUERY_DEFAULT_CONFIG_PLUGIN
+ FLAGS_config_retriever = STR(OSQUERY_DEFAULT_CONFIG_PLUGIN);
+#endif
+ auto config = Config::getInstance();
+ config->load();
}
}
+++ /dev/null
-// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-// rights reserved.
-
-// License to copy and use this software is granted provided that it
-// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-// Algorithm" in all material mentioning or referencing this software
-// or this function.
-//
-// License is also granted to make and use derivative works provided
-// that such works are identified as "derived from the RSA Data
-// Security, Inc. MD5 Message-Digest Algorithm" in all material
-// mentioning or referencing the derived work.
-//
-// RSA Data Security, Inc. makes no representations concerning either
-// the merchantability of this software or the suitability of this
-// software for any particular purpose. It is provided "as is"
-// without express or implied warranty of any kind.
-//
-// These notices must be retained in any copies of any part of this
-// documentation and/or software.
-
-// The original md5 implementation avoids external libraries.
-// This version has dependency on stdio.h for file input and
-// string.h for memcpy.
-
-#pragma once
-
-#include <stdio.h>
-#include <string.h>
-
-namespace osquery {
-namespace md5 {
-
-// Constants for MD5Transform routine.
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-static unsigned char PADDING[64] = {0x80,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0};
-
-// F, G, H and I are basic MD5 functions.
-#define FFF(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-// ROTATE_LEFT rotates x left n bits.
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-// Rotation is separate from addition to prevent recomputation.
-#define FF(a, b, c, d, x, s, ac) \
- { \
- (a) += FFF((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) \
- { \
- (a) += G((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) \
- { \
- (a) += H((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) \
- { \
- (a) += I((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT((a), (s)); \
- (a) += (b); \
- }
-
-typedef unsigned char BYTE;
-
-// POINTER defines a generic pointer type
-typedef unsigned char *POINTER;
-
-// UINT2 defines a two byte word
-typedef unsigned short int UINT2;
-
-// UINT4 defines a four byte word
-typedef unsigned long int UINT4;
-
-// convenient object that wraps
-// the C-functions for use in C++ only
-class MD5 {
- private:
- struct __context_t {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
- } context;
-
- // The core of the MD5 algorithm is here.
- // MD5 basic transformation. Transforms state based on block.
- static void MD5Transform(UINT4 state[4], unsigned char block[64]) {
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode(x, block, 64);
-
- /* Round 1 */
- FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
- FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
- FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
- FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
- FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
- FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
- FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
- FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
- FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
- FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
- FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
- GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
- GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
- GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
- GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
- GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
- GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
- GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
- GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
- GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
- GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
- HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
- HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
- HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
- HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
- HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
- HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
- HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
- HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
- HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
- II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
- II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
- II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
- II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
- II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
- II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
- II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
- II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
- II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- // Zeroize sensitive information.
- memset((POINTER)x, 0, sizeof(x));
- }
-
- // Encodes input (UINT4) into output (unsigned char). Assumes len is
- // a multiple of 4.
- static void Encode(unsigned char *output, UINT4 *input, unsigned int len) {
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
- }
-
- // Decodes input (unsigned char) into output (UINT4). Assumes len is
- // a multiple of 4.
- static void Decode(UINT4 *output, unsigned char *input, unsigned int len) {
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j + 1]) << 8) |
- (((UINT4)input[j + 2]) << 16) | (((UINT4)input[j + 3]) << 24);
- }
- }
-
- public:
- // MAIN FUNCTIONS
- MD5() { Init(); }
-
- // MD5 initialization. Begins an MD5 operation, writing a new context.
- void Init() {
- context.count[0] = context.count[1] = 0;
-
- // Load magic initialization constants.
- context.state[0] = 0x67452301;
- context.state[1] = 0xefcdab89;
- context.state[2] = 0x98badcfe;
- context.state[3] = 0x10325476;
- }
-
- // MD5 block update operation. Continues an MD5 message-digest
- // operation, processing another message block, and updating the
- // context.
- void Update(unsigned char *input, unsigned int inputLen) {
- unsigned int i, index, partLen;
-
- // Compute number of bytes mod 64
- index = (unsigned int)((context.count[0] >> 3) & 0x3F);
-
- // Update number of bits
- if ((context.count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) {
- context.count[1]++;
- }
- context.count[1] += ((UINT4)inputLen >> 29);
-
- partLen = 64 - index;
-
- // Transform as many times as possible.
- if (inputLen >= partLen) {
- memcpy((POINTER)&context.buffer[index], (POINTER)input, partLen);
- MD5Transform(context.state, context.buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64) {
- MD5Transform(context.state, &input[i]);
- }
- index = 0;
- } else {
- i = 0;
- }
-
- /* Buffer remaining input */
- memcpy((POINTER)&context.buffer[index], (POINTER)&input[i], inputLen - i);
- }
-
- // MD5 finalization. Ends an MD5 message-digest operation, writing the
- // the message digest and zeroizing the context.
- // Writes to digestRaw
- void Final() {
- unsigned char bits[8];
- unsigned int index, padLen;
-
- // Save number of bits
- Encode(bits, context.count, 8);
-
- // Pad out to 56 mod 64.
- index = (unsigned int)((context.count[0] >> 3) & 0x3f);
- padLen = (index < 56) ? (56 - index) : (120 - index);
- Update(PADDING, padLen);
-
- // Append length (before padding)
- Update(bits, 8);
-
- // Store state in digest
- Encode(digestRaw, context.state, 16);
-
- // Zeroize sensitive information.
- memset((POINTER)&context, 0, sizeof(context));
-
- writeToString();
- }
-
- /// Buffer must be 32+1 (nul) = 33 chars long at least
- void writeToString() {
- int pos;
-
- for (pos = 0; pos < 16; pos++)
- sprintf(digestChars + (pos * 2), "%02x", digestRaw[pos]);
- }
-
- public:
- // an MD5 digest is a 16-byte number (32 hex digits)
- BYTE digestRaw[16];
-
- // This version of the digest is actually
- // a "printf'd" version of the digest.
- char digestChars[33];
-
- /// Load a file from disk and digest it
- // Digests a file and returns the result.
- char *digestFile(const char *filename) {
- Init();
-
- FILE *file;
-
- int len;
- unsigned char buffer[1024];
-
- if ((file = fopen(filename, "rb")) == nullptr) {
- fprintf(stderr, "%s can't be opened\n", filename);
- } else {
- while ((len = fread(buffer, 1, 1024, file))) {
- Update(buffer, len);
- }
- Final();
-
- fclose(file);
- }
-
- return digestChars;
- }
-
- /// Digests a byte-array already in memory
- char *digestMemory(BYTE *memchunk, int len) {
- Init();
- Update(memchunk, len);
- Final();
-
- return digestChars;
- }
-
- // Digests a string and prints the result.
- char *digestString(const char *string) {
- Init();
- Update((unsigned char *)string, strlen(string));
- Final();
-
- return digestChars;
- }
-};
-}
-}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <sstream>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+#include <osquery/core.h>
#include <osquery/database.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
-#include <osquery/core.h>
-
#include "osquery/core/sqlite_util.h"
#include "osquery/core/virtual_table.h"
QueryData query(const std::string& q, int& error_return, sqlite3* db) {
QueryData d;
char* err = nullptr;
- sqlite3_exec(db, q.c_str(), core::query_data_callback, &d, &err);
+ sqlite3_exec(db, q.c_str(), query_data_callback, &d, &err);
if (err != nullptr) {
LOG(ERROR) << "Error launching query: " << err;
error_return = 1;
return d;
}
-namespace core {
-
int query_data_callback(void* argument,
int argc,
char* argv[],
return 0;
}
}
-}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
namespace osquery {
-namespace core {
// the callback for populating a std::vector<row> set of results. "argument"
// should be a non-const reference to a std::vector<row>
int query_data_callback(void *argument, int argc, char *argv[], char *column[]);
}
-}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <osquery/core.h>
-#include "osquery/core/sqlite_util.h"
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <iostream>
#include <gtest/gtest.h>
+#include <osquery/core.h>
+
+#include "osquery/core/sqlite_util.h"
#include "osquery/core/test_util.h"
namespace osquery {
-namespace core {
class SQLiteUtilTests : public testing::Test {};
EXPECT_EQ(err, 0);
}
}
-}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/status.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <sstream>
#include <sys/types.h>
#include <signal.h>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
-#include <glog/logging.h>
-
#include <osquery/core.h>
#include <osquery/database/db_handle.h>
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
#include <osquery/sql.h>
namespace fs = boost::filesystem;
std::string getHostname() {
char hostname[256]; // Linux max should be 64.
- memset(hostname, 0, 256);
- gethostname(hostname, 255);
+ memset(hostname, 0, sizeof(hostname));
+ gethostname(hostname, sizeof(hostname) - 1);
std::string hostname_string = std::string(hostname);
boost::algorithm::trim(hostname_string);
return hostname_string;
#ifdef __APPLE__
// Use the hardware uuid available on OSX to identify this machine
char uuid[128];
- memset(uuid, 0, 128);
+ memset(uuid, 0, sizeof(uuid));
uuid_t id;
// wait at most 5 seconds for gethostuuid to return
const timespec wait = {5, 0};
return results;
}
+Status checkStalePid(const std::string& pidfile_content) {
+ int pid;
+ try {
+ pid = stoi(pidfile_content);
+ } catch (const std::invalid_argument& e) {
+ return Status(1, std::string("Could not parse pidfile: ") + e.what());
+ }
+
+ int status = kill(pid, 0);
+ if (status != ESRCH) {
+ // The pid is running, check if it is an osqueryd process by name.
+ std::stringstream query_text;
+ query_text << "SELECT name FROM processes WHERE pid = " << pid << ";";
+ auto q = SQL(query_text.str());
+ if (!q.ok()) {
+ return Status(1, "Error querying processes: " + q.getMessageString());
+ }
+
+ if (q.rows().size() >= 1 && q.rows().front()["name"] == "osqueryd") {
+ // If the process really is osqueryd, return an "error" status.
+ return Status(1,
+ std::string("osqueryd (") + pidfile_content +
+ ") is already running");
+ } else {
+ LOG(INFO) << "Found stale process for osqueryd (" << pidfile_content
+ << ") removing pidfile.";
+ }
+ }
+
+ // Now the pidfile is either the wrong pid or the pid is not running.
+ try {
+ boost::filesystem::remove(FLAGS_pidfile);
+ } catch (boost::filesystem::filesystem_error& e) {
+ // Unable to remove old pidfile.
+ LOG(WARNING) << "Unable to remove the osqueryd pidfile.";
+ }
+
+ return Status(0, "OK");
+}
+
Status createPidFile() {
// check if pidfile exists
auto exists = pathExists(FLAGS_pidfile);
if (exists.ok()) {
- // if it exists, check if that pid is running
+ // if it exists, check if that pid is running.
std::string content;
auto read_status = readFile(FLAGS_pidfile, content);
if (!read_status.ok()) {
return Status(1, "Could not read pidfile: " + read_status.toString());
}
- int osqueryd_pid;
- try {
- osqueryd_pid = stoi(content);
- } catch (const std::invalid_argument& e) {
- return Status(
- 1,
- std::string("Could not convert pidfile content to an int: ") +
- std::string(e.what()));
- }
- if (kill(osqueryd_pid, 0) == 0) {
- // if the pid is running, return an "error" status
- return Status(1, "osqueryd is already running");
- } else if (errno == ESRCH) {
- // if the pid isn't running, overwrite the pidfile
- try {
- boost::filesystem::remove(FLAGS_pidfile);
- } catch (boost::filesystem::filesystem_error& e) {
- // Unable to remove old pidfile.
- }
- goto write_new_pidfile;
- } else {
- return Status(
- 1,
- std::string(
- "An unknown error occured checking if the pid is running: ") +
- std::string(strerror(errno)));
+ auto stale_status = checkStalePid(content);
+ if (!stale_status.ok()) {
+ return stale_status;
}
- } else {
- // if it doesn't exist, write a pid file and return a "success" status
- write_new_pidfile:
- auto current_pid = boost::lexical_cast<std::string>(getpid());
- LOG(INFO) << "Writing pid (" << current_pid << ") to " << FLAGS_pidfile;
- auto write_status = writeTextFile(FLAGS_pidfile, current_pid, 0755);
- return write_status;
}
+
+ // If no pidfile exists or the existing pid was stale, write, log, and run.
+ auto pid = boost::lexical_cast<std::string>(getpid());
+ LOG(INFO) << "Writing osqueryd pid (" << pid << ") to " << FLAGS_pidfile;
+ auto status = writeTextFile(FLAGS_pidfile, pid, 0644);
+ return status;
}
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/logger.h>
#include <osquery/tables.h>
namespace tables {
bool ConstraintList::matches(const std::string& expr) {
- // Support each affinity type casting.
+ // Support each SQL affinity type casting.
if (affinity == "TEXT") {
return literal_matches<TEXT_LITERAL>(expr);
} else if (affinity == "INTEGER") {
template <typename T>
bool ConstraintList::literal_matches(const T& base_expr) {
bool aggregate = true;
- for (size_t i = 0; i < constraints.size(); ++i) {
- T constraint_expr = AS_LITERAL(T, constraints[i].expr);
- if (constraints[i].op == EQUALS) {
+ for (size_t i = 0; i < constraints_.size(); ++i) {
+ T constraint_expr = AS_LITERAL(T, constraints_[i].expr);
+ if (constraints_[i].op == EQUALS) {
aggregate = aggregate && (base_expr == constraint_expr);
- } else if (constraints[i].op == GREATER_THAN) {
+ } else if (constraints_[i].op == GREATER_THAN) {
aggregate = aggregate && (base_expr > constraint_expr);
- } else if (constraints[i].op == LESS_THAN) {
+ } else if (constraints_[i].op == LESS_THAN) {
aggregate = aggregate && (base_expr < constraint_expr);
- } else if (constraints[i].op == GREATER_THAN_OR_EQUALS) {
+ } else if (constraints_[i].op == GREATER_THAN_OR_EQUALS) {
aggregate = aggregate && (base_expr >= constraint_expr);
- } else if (constraints[i].op == LESS_THAN_OR_EQUALS) {
+ } else if (constraints_[i].op == LESS_THAN_OR_EQUALS) {
aggregate = aggregate && (base_expr <= constraint_expr);
} else {
// Unsupported constraint.
std::vector<std::string> ConstraintList::getAll(ConstraintOperator op) {
std::vector<std::string> set;
- for (size_t i = 0; i < constraints.size(); ++i) {
- if (constraints[i].op == op) {
+ for (size_t i = 0; i < constraints_.size(); ++i) {
+ if (constraints_[i].op == op) {
// TODO: this does not apply a distinct.
- set.push_back(constraints[i].expr);
+ set.push_back(constraints_[i].expr);
}
}
return set;
}
-
-template <typename T>
-bool ConstraintList::existsAndMatches(const T& expr) {
- return (exists() && literal_matches<T>(expr));
-}
-
-template <typename T>
-bool ConstraintList::notExistsOrMatches(const T& expr) {
- return (!exists() || literal_matches<T>(expr));
-}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <gtest/gtest.h>
+
+#include <osquery/tables.h>
+
+namespace osquery {
+namespace tables {
+
+class TablesTests : public testing::Test {};
+
+TEST_F(TablesTests, test_constraint) {
+ auto constraint = Constraint(EQUALS);
+ constraint.expr = "none";
+
+ EXPECT_EQ(constraint.op, EQUALS);
+ EXPECT_EQ(constraint.expr, "none");
+}
+
+TEST_F(TablesTests, test_constraint_list) {
+ struct ConstraintList cl;
+
+ auto constraint = Constraint(EQUALS);
+ constraint.expr = "some";
+
+ // The constraint list is a simple struct.
+ cl.add(constraint);
+ EXPECT_EQ(cl.constraints_.size(), 1);
+
+ constraint = Constraint(EQUALS);
+ constraint.expr = "some_other";
+ cl.add(constraint);
+
+ constraint = Constraint(GREATER_THAN);
+ constraint.expr = "more_than";
+ cl.add(constraint);
+ EXPECT_EQ(cl.constraints_.size(), 3);
+
+ auto all_equals = cl.getAll(EQUALS);
+ EXPECT_EQ(all_equals.size(), 2);
+}
+
+TEST_F(TablesTests, test_constraint_matching) {
+ struct ConstraintList cl;
+ // An empty constraint list has expectations.
+ EXPECT_FALSE(cl.exists());
+ EXPECT_TRUE(cl.notExistsOrMatches("some"));
+
+ auto constraint = Constraint(EQUALS);
+ constraint.expr = "some";
+ cl.add(constraint);
+
+ EXPECT_TRUE(cl.exists());
+ EXPECT_TRUE(cl.notExistsOrMatches("some"));
+ EXPECT_TRUE(cl.matches("some"));
+ EXPECT_FALSE(cl.notExistsOrMatches("not_some"));
+
+ struct ConstraintList cl2;
+ cl2.affinity = "INTEGER";
+ constraint = Constraint(LESS_THAN);
+ constraint.expr = "1000";
+ cl2.add(constraint);
+ constraint = Constraint(GREATER_THAN);
+ constraint.expr = "1";
+ cl2.add(constraint);
+
+ // Test both SQL-provided string types.
+ EXPECT_TRUE(cl2.matches("10"));
+ // ...and the type literal.
+ EXPECT_TRUE(cl2.matches(10));
+
+ // Test operator lower bounds.
+ EXPECT_FALSE(cl2.matches(0));
+ EXPECT_FALSE(cl2.matches(1));
+
+ // Test operator upper bounds.
+ EXPECT_FALSE(cl2.matches(1000));
+ EXPECT_FALSE(cl2.matches(1001));
+
+ // Now test inclusive bounds.
+ struct ConstraintList cl3;
+ constraint = Constraint(LESS_THAN_OR_EQUALS);
+ constraint.expr = "1000";
+ cl3.add(constraint);
+ constraint = Constraint(GREATER_THAN_OR_EQUALS);
+ constraint.expr = "1";
+ cl3.add(constraint);
+
+ EXPECT_FALSE(cl3.matches(1001));
+ EXPECT_TRUE(cl3.matches(1000));
+
+ EXPECT_FALSE(cl3.matches(0));
+ EXPECT_TRUE(cl3.matches(1));
+}
+
+TEST_F(TablesTests, test_constraint_map) {
+ ConstraintMap cm;
+ ConstraintList cl;
+
+ cl.add(Constraint(EQUALS, "some"));
+ cm["path"] = cl;
+
+ EXPECT_TRUE(cm["path"].matches("some"));
+}
+}
+}
+
+int main(int argc, char* argv[]) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "osquery/core/test_util.h"
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <deque>
#include <sstream>
#include <boost/property_tree/json_parser.hpp>
-#include <glog/logging.h>
+#include <osquery/filesystem.h>
+#include <osquery/logger.h>
#include "osquery/core/sqlite_util.h"
-#include <osquery/filesystem.h>
+#include "osquery/core/test_util.h"
namespace pt = boost::property_tree;
namespace osquery {
-namespace core {
const std::string kTestQuery = "SELECT * FROM test_table";
+const std::string kTestDataPath = "../../../tools/tests/";
sqlite3* createTestDB() {
sqlite3* db = createDB();
}
std::string getCACertificateContent() {
- std::string content = R"(
-MIIESzCCAzOgAwIBAgIJAI1bGeY2YPlhMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD
-VQQGEwItLTESMBAGA1UECAwJU29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZ
-MBcGA1UECgwQU29tZU9yZ2FuaXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXph
-dGlvbmFsVW5pdDEeMBwGA1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJ
-KoZIhvcNAQkBFhpyb290QGxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xNDA4MTkx
-OTEyMTZaFw0xNTA4MTkxOTEyMTZaMIG7MQswCQYDVQQGEwItLTESMBAGA1UECAwJ
-U29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZMBcGA1UECgwQU29tZU9yZ2Fu
-aXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXphdGlvbmFsVW5pdDEeMBwGA1UE
-AwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJKoZIhvcNAQkBFhpyb290QGxv
-Y2FsaG9zdC5sb2NhbGRvbWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAM6EsaVoMaHrYqH/s4YlhF6ke1XmUhzksB2eqpNqdgZw1JcZi9droRpuYmIf
-bNyvWqUffHW9mKRv+udF5Woueshn+7Kj9YnnL9jfMzFaVEC8WRwWk54RIdNkxgFq
-dqlaiwBWLvZkNUS9k/nugxVTbNu/GTqQlUG1XsIWBDJ2qRqniRfMKrfBKOxPYCZA
-l7KeFguRA+xOsA7/71OMXJZKneMSWN8duTQCFt7uYCQXWc/IV6BfKTaR/ZQQ4w7/
-iEMYPMZPSNprjun7rx0r2zPZGyrkGSCiS+4e+dfy0NbmYXodGHDxb/vBlm4q8CqF
-OoH9aq0F/3581uZcuvU2ydX/LWcCAwEAAaNQME4wHQYDVR0OBBYEFPK5mwDg7mDV
-fEJs4+ZOP9xvZBHAMB8GA1UdIwQYMBaAFPK5mwDg7mDVfEJs4+ZOP9xvZBHAMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKNNP6f0JKxBtfq8hakrhHyl
-cSN83SmVPcrsTLeaW8w0hi+JOtNOjD9sM8KNSbmLXfhRH4yPqYV+0dpJi5+SeelW
-DjxZwbcFoI4EEu+zqufTUpu0T51eqnGvIedlIu1i2CiaoAJEmAN2OKQuN7uIQW27
-2gL/RS+DVkevaidLRh7q2QI23B0n1XZuyEUiUKB1YfTPrupMZkostuyGybAJaxrc
-ONmxUsB38pWJRCef9N/5APS74uIesfxSvEZXcXfPA+wrQY0yXn+bsEhz9pJOxZvD
-WxULUHBC6qH9gAlKEqZYS3CwpCEl/Blznwi30r4CwwQ6dLfeXoPQDxAt7LyPpV4=
-)";
+ std::string content;
+ readFile(kTestDataPath + "test_cert.pem", content);
return content;
}
std::string getEtcHostsContent() {
- std::string content = R"(
-##
-#Host Database
-#
-#localhost is used to configure the loopback interface
-#when the system is booting.Do not change this entry.
-##
-127.0.0.1 localhost
-255.255.255.255 broadcasthost
-::1 localhost
-fe80::1%lo0 localhost
-)";
+ std::string content;
+ readFile(kTestDataPath + "test_hosts.txt", content);
return content;
}
return {row1, row2, row3, row4};
}
}
-}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <osquery/filesystem.h>
namespace osquery {
-namespace core {
// kTestQuery is a test query that can be executed against the database
// returned from createTestDB() to result in the dataset returned from
// getTestDBExpectedResults()
extern const std::string kTestQuery;
+extern const std::string kTestDataPath;
// createTestDB instantiates a sqlite3 struct and populates it with some test
// data
// generate the expected data that getEtcHostsContent() should parse into
osquery::QueryData getEtcHostsExpectedResults();
-// the three items that you need to test osquery::core::splitString
+// the three items that you need to test osquery::splitString
struct SplitStringTestData {
std::string test_string;
std::string delim;
std::vector<std::string> test_vector;
};
-// generate a set of test data to test osquery::core::splitString
+// generate a set of test data to test osquery::splitString
std::vector<SplitStringTestData> generateSplitStringTestData();
}
-}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <glog/logging.h>
#include <sqlite3.h>
#include <osquery/core.h>
+#include <osquery/logger.h>
+
#include "osquery/core/test_util.h"
namespace osquery {
-namespace core {
class TestUtilTests : public testing::Test {};
sqlite3_close(db);
}
}
-}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/core.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <osquery/core.h>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <glog/logging.h>
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
#include "osquery/core/test_util.h"
namespace osquery {
-namespace core {
class TextTests : public testing::Test {};
}
}
}
-}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/logger.h>
+
#include "osquery/core/virtual_table.h"
namespace osquery {
void attachVirtualTables(sqlite3 *db) {
for (const auto &table : REGISTERED_TABLES) {
- VLOG(1) << "Attaching virtual table: " << table.first;
int s = table.second->attachVtable(db);
if (s != SQLITE_OK) {
LOG(ERROR) << "Error attaching virtual table: " << table.first << " ("
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
#include <map>
-#include <sqlite3.h>
#include <stdio.h>
-#include <osquery/tables.h>
+#include <sqlite3.h>
+
#include <osquery/registry.h>
+#include <osquery/tables.h>
namespace osquery {
namespace tables {
-/// Helper alias for TablePlugin names.
-typedef const std::string TableName;
-typedef const std::vector<std::pair<std::string, std::string> > TableColumns;
-typedef std::map<std::string, std::vector<std::string> > TableData;
-
/**
* @brief osquery cursor object.
*
TABLE_PLUGIN *pContent;
};
-/**
- * @brief The TablePlugin defines the name, types, and column information.
- *
- * To attach a virtual table create a TablePlugin subclass and register the
- * virtual table name as the plugin ID. osquery will enumerate all registered
- * TablePlugins and attempt to attach them to SQLite at instanciation.
- */
-class TablePlugin {
- public:
- TableName name;
- TableColumns columns;
- /// Helper method to generate the virtual table CREATE statement.
- std::string statement(TableName name, TableColumns columns);
-
- public:
- /// Part of the query state, number of rows generated.
- int n;
- /// Part of the query state, column data returned from a query.
- TableData data;
- /// Part of the query state, parsed set of query predicate constraints.
- ConstraintSet constraints;
-
- public:
- virtual int attachVtable(sqlite3 *db) { return -1; }
- virtual ~TablePlugin(){};
-
- protected:
- TablePlugin(){};
-};
-
-typedef std::shared_ptr<TablePlugin> TablePluginRef;
-
int xOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int xClose(sqlite3_vtab_cursor *cur);
template <typename T>
static int xBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {
auto *pContent = ((x_vtab<T> *)tab)->pContent;
+ pContent->constraints.clear();
int expr_index = 0;
+ int cost = 0;
for (size_t i = 0; i < pIdxInfo->nConstraint; ++i) {
if (!pIdxInfo->aConstraint[i].usable) {
+ // A higher cost less priority, prefer more usable query constraints.
+ cost += 10;
// TODO: OR is not usable.
continue;
}
- const auto &name =
+ const auto& name =
pContent->columns[pIdxInfo->aConstraint[i].iColumn].first;
pContent->constraints.push_back(
std::make_pair(name, Constraint(pIdxInfo->aConstraint[i].op)));
pIdxInfo->aConstraintUsage[i].argvIndex = ++expr_index;
}
+ pIdxInfo->estimatedCost = cost;
return SQLITE_OK;
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
#include <mutex>
#include <stdexcept>
-#include <glog/logging.h>
#include <rocksdb/env.h>
#include <rocksdb/options.h>
#include <osquery/database/db_handle.h>
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
#include <osquery/status.h>
namespace osquery {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
#include <boost/filesystem/operations.hpp>
-#include <glog/logging.h>
#include <gtest/gtest.h>
#include <osquery/database/db_handle.h>
+#include <osquery/tables.h>
const std::string kTestingDBHandlePath = "/tmp/rocksdb-osquery-dbhandletests";
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
#include <ctime>
#include "osquery/core/test_util.h"
-using namespace osquery::core;
-
const std::string kTestingQueryDBPath = "/tmp/rocksdb-osquery-querytests";
namespace osquery {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/property_tree/json_parser.hpp>
-#include <glog/logging.h>
-
#include <osquery/database/results.h>
+#include <osquery/logger.h>
namespace pt = boost::property_tree;
using osquery::Status;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <sstream>
#include <string>
#include <vector>
-#include <glog/logging.h>
#include <gtest/gtest.h>
#include <osquery/database/results.h>
+#include <osquery/logger.h>
#include "osquery/core/test_util.h"
namespace pt = boost::property_tree;
-using namespace osquery::core;
-
namespace osquery {
class ResultsTests : public testing::Test {};
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <iostream>
#include <sstream>
-#include <glog/logging.h>
-
#include <osquery/core.h>
#include <osquery/devtools.h>
+#include <osquery/logger.h>
namespace osquery {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <glog/logging.h>
#include <osquery/devtools.h>
+#include <osquery/logger.h>
namespace osquery {
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <glog/logging.h>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/dispatcher.h>
#include <osquery/flags.h>
+#include <osquery/logger.h>
#include "osquery/core/conversions.h"
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#define GTEST_HAS_TR1_TUPLE 0
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <exception>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
10, // 10 seconds
};
-void EventPublisher::fire(const EventContextRef ec, EventTime time) {
+void EventPublisherCore::fire(const EventContextRef& ec, EventTime time) {
EventContextID ec_id;
+ if (isEnding()) {
+ // Cannot emit/fire while ending
+ return;
+ }
+
{
boost::lock_guard<boost::mutex> lock(ec_id_lock_);
ec_id = next_ec_id_++;
}
for (const auto& subscription : subscriptions_) {
- auto callback = subscription->callback;
- if (shouldFire(subscription->context, ec) && callback != nullptr) {
- callback(ec, false);
- }
+ fireCallback(subscription, ec);
}
}
-bool EventPublisher::shouldFire(const SubscriptionContextRef mc,
- const EventContextRef ec) {
- return true;
-}
-
-Status EventPublisher::run() {
- // Runloops/entrypoints are ONLY implemented if needed.
- return Status(1, "No runloop required");
-}
-
-std::vector<std::string> EventSubscriber::getIndexes(EventTime start,
+std::vector<std::string> EventSubscriberCore::getIndexes(EventTime start,
EventTime stop,
int list_key) {
auto db = DBHandle::getInstance();
// Keep track of the tail/head of account time while bin searching.
EventTime start_max = stop, stop_min = stop, local_start, local_stop;
auto types = kEventTimeLists.size();
- // Binning keys are the list_type:list_id pairs representing bins of records.
- std::vector<std::string> binning_keys;
// List types are sized bins of time containing records for this namespace.
for (size_t i = 0; i < types; ++i) {
auto size = kEventTimeLists[i];
return indexes;
}
-Status EventSubscriber::expireIndexes(
+Status EventSubscriberCore::expireIndexes(
const std::string& list_type,
const std::vector<std::string>& indexes,
const std::vector<std::string>& expirations) {
return Status(0, "OK");
}
-std::vector<EventRecord> EventSubscriber::getRecords(
+std::vector<EventRecord> EventSubscriberCore::getRecords(
const std::vector<std::string>& indexes) {
auto db = DBHandle::getInstance();
auto record_key = "records." + dbNamespace();
return records;
}
-Status EventSubscriber::recordEvent(EventID eid, EventTime time) {
+Status EventSubscriberCore::recordEvent(EventID& eid, EventTime time) {
Status status;
auto db = DBHandle::getInstance();
std::string time_value = boost::lexical_cast<std::string>(time);
return Status(0, "OK");
}
-EventID EventSubscriber::getEventID() {
+EventID EventSubscriberCore::getEventID() {
Status status;
auto db = DBHandle::getInstance();
// First get an event ID from the meta key.
return eid_value;
}
-QueryData EventSubscriber::get(EventTime start, EventTime stop) {
+QueryData EventSubscriberCore::get(EventTime start, EventTime stop) {
QueryData results;
Status status;
- auto db = DBHandle::getInstance();
+
+ std::shared_ptr<DBHandle> db;
+ try {
+ db = DBHandle::getInstance();
+ } catch (const std::runtime_error& e) {
+ LOG(ERROR) << "Cannot retrieve subscriber results database is locked";
+ return results;
+ }
// Get the records for this time range.
auto indexes = getIndexes(start, stop);
return results;
}
-Status EventSubscriber::add(const Row& r, EventTime time) {
+Status EventSubscriberCore::add(const Row& r, EventTime time) {
Status status;
- auto db = DBHandle::getInstance();
+
+ std::shared_ptr<DBHandle> db;
+ try {
+ db = DBHandle::getInstance();
+ } catch (const std::runtime_error& e) {
+ return Status(1, e.what());
+ }
// Get and increment the EID for this module.
EventID eid = getEventID();
void EventFactory::delay() {
auto& ef = EventFactory::getInstance();
- for (const auto& eventtype : EventFactory::getInstance().event_pubs_) {
+ for (const auto& publisher : EventFactory::getInstance().event_pubs_) {
auto thread_ = std::make_shared<boost::thread>(
- boost::bind(&EventFactory::run, eventtype.first));
+ boost::bind(&EventFactory::run, publisher.first));
ef.threads_.push_back(thread_);
}
}
-Status EventFactory::run(EventPublisherID type_id) {
+Status EventFactory::run(EventPublisherID& type_id) {
// An interesting take on an event dispatched entrypoint.
// There is little introspection into the event type.
// Assume it can either make use of an entrypoint poller/selector or
}
auto status = Status(0, "OK");
- while (!EventFactory::getInstance().ending_ && status.ok()) {
+ while (!event_pub->isEnding() && status.ok()) {
// Can optionally implement a global cooloff latency here.
status = event_pub->run();
::usleep(20);
}
// The runloop status is not reflective of the event type's.
+ VLOG(1) << "Event publisher " << event_pub->type() << " has terminated";
return Status(0, "OK");
}
void EventFactory::end(bool should_end) {
- EventFactory::getInstance().ending_ = should_end;
- // Join on the thread group.
+ auto& ef = EventFactory::getInstance();
+
+ for (const auto& publisher : ef.event_pubs_) {
+ publisher.second->shouldEnd(should_end);
+ }
+
+ // Stop handling exceptions for the publisher threads.
+ for (const auto& thread : ef.threads_) {
+ thread->detach();
+ }
+
::usleep(400);
+ ef.threads_.clear();
}
// There's no reason for the event factory to keep multiple instances.
return ef;
}
-Status EventFactory::registerEventPublisher(const EventPublisherRef event_pub) {
+Status EventFactory::registerEventPublisher(const EventPublisherRef& pub) {
auto& ef = EventFactory::getInstance();
- auto type_id = event_pub->type();
+ auto type_id = pub->type();
if (ef.getEventPublisher(type_id) != nullptr) {
// This is a duplicate type id?
return Status(1, "Duplicate Event Type");
}
- if (!event_pub->setUp().ok()) {
+ if (!pub->setUp().ok()) {
// Only add the publisher if setUp was successful.
return Status(1, "SetUp failed.");
}
- ef.event_pubs_[type_id] = event_pub;
+ ef.event_pubs_[type_id] = pub;
return Status(0, "OK");
}
Status EventFactory::registerEventSubscriber(
- const EventSubscriberRef event_module) {
+ const EventSubscriberRef& event_module) {
auto& ef = EventFactory::getInstance();
// Let the module initialize any Subscriptions.
event_module->init();
- ef.event_modules_.push_back(event_module);
+ ef.event_subs_[event_module->name()] = event_module;
return Status(0, "OK");
}
-Status EventFactory::addSubscription(EventPublisherID type_id,
- const SubscriptionRef subscription) {
+Status EventFactory::addSubscription(EventPublisherID& type_id,
+ const SubscriptionContextRef& mc,
+ EventCallback cb) {
+ auto subscription = Subscription::create(mc, cb);
+ return EventFactory::addSubscription(type_id, subscription);
+}
+
+Status EventFactory::addSubscription(EventPublisherID& type_id,
+ const SubscriptionRef& subscription) {
auto event_pub = EventFactory::getInstance().getEventPublisher(type_id);
if (event_pub == nullptr) {
// Cannot create a Subscription for a missing type_id.
return status;
}
-Status EventFactory::addSubscription(EventPublisherID type_id,
- const SubscriptionContextRef mc,
- EventCallback cb) {
- auto subscription = Subscription::create(mc, cb);
- return EventFactory::addSubscription(type_id, subscription);
-}
-
-size_t EventFactory::numSubscriptions(EventPublisherID type_id) {
+size_t EventFactory::numSubscriptions(EventPublisherID& type_id) {
const auto& event_pub =
EventFactory::getInstance().getEventPublisher(type_id);
if (event_pub != nullptr) {
return 0;
}
-std::shared_ptr<EventPublisher> EventFactory::getEventPublisher(
- EventPublisherID type_id) {
+EventPublisherRef EventFactory::getEventPublisher(EventPublisherID& type_id) {
auto& ef = EventFactory::getInstance();
const auto& it = ef.event_pubs_.find(type_id);
if (it != ef.event_pubs_.end()) {
return nullptr;
}
-Status EventFactory::deregisterEventPublisher(
- const EventPublisherRef event_pub) {
- return EventFactory::deregisterEventPublisher(event_pub->type());
+EventSubscriberRef EventFactory::getEventSubscriber(
+ EventSubscriberID& name_id) {
+ auto& ef = EventFactory::getInstance();
+ const auto& it = ef.event_subs_.find(name_id);
+ if (it != ef.event_subs_.end()) {
+ return ef.event_subs_[name_id];
+ }
+ return nullptr;
+}
+
+Status EventFactory::deregisterEventPublisher(const EventPublisherRef& pub) {
+ return EventFactory::deregisterEventPublisher(pub->type());
}
-Status EventFactory::deregisterEventPublisher(EventPublisherID type_id) {
+Status EventFactory::deregisterEventPublisher(EventPublisherID& type_id) {
auto& ef = EventFactory::getInstance();
const auto& it = ef.event_pubs_.find(type_id);
if (it == ef.event_pubs_.end()) {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/operations.hpp>
#include <osquery/events.h>
#include <osquery/tables.h>
-#include "osquery/core/test_util.h"
+namespace osquery {
const std::string kTestingEventsDBPath = "/tmp/rocksdb-osquery-testevents";
-namespace osquery {
-
class EventsDatabaseTests : public ::testing::Test {
public:
void SetUp() {
}
};
-class FakeEventSubscriber : public EventSubscriber {
- DECLARE_EVENTSUBSCRIBER(FakeEventSubscriber, FakeEventPublisher);
+class FakeEventPublisher
+ : public EventPublisher<SubscriptionContext, EventContext> {
+ DECLARE_PUBLISHER("FakePublisher");
+};
+
+class FakeEventSubscriber : public EventSubscriber<FakeEventPublisher> {
+ DECLARE_SUBSCRIBER("FakeSubscriber");
public:
/// Add a fake event at time t
}
};
-class FakeEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(FakeEventPublisher, SubscriptionContext, EventContext);
-};
-
-class AnotherFakeEventSubscriber : public EventSubscriber {
- DECLARE_EVENTSUBSCRIBER(AnotherFakeEventSubscriber, FakeEventPublisher);
-};
-
TEST_F(EventsDatabaseTests, test_event_module_id) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
- fake_event_module->doNotExpire();
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ sub->doNotExpire();
+
// Not normally available outside of EventSubscriber->Add().
- auto event_id1 = fake_event_module->getEventID();
+ auto event_id1 = sub->getEventID();
EXPECT_EQ(event_id1, "1");
- auto event_id2 = fake_event_module->getEventID();
+ auto event_id2 = sub->getEventID();
EXPECT_EQ(event_id2, "2");
}
-TEST_F(EventsDatabaseTests, test_unique_event_module_id) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
- auto another_fake_event_module = AnotherFakeEventSubscriber::getInstance();
- // Not normally available outside of EventSubscriber->Add().
- auto event_id1 = fake_event_module->getEventID();
- EXPECT_EQ(event_id1, "3");
- auto event_id2 = another_fake_event_module->getEventID();
- EXPECT_EQ(event_id2, "1");
-}
TEST_F(EventsDatabaseTests, test_event_add) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
- auto status = fake_event_module->testAdd(1);
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ auto status = sub->testAdd(1);
EXPECT_TRUE(status.ok());
}
TEST_F(EventsDatabaseTests, test_record_indexing) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
- auto status = fake_event_module->testAdd(2);
- status = fake_event_module->testAdd(11);
- status = fake_event_module->testAdd(61);
- status = fake_event_module->testAdd((1 * 3600) + 1);
- status = fake_event_module->testAdd((2 * 3600) + 1);
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ auto status = sub->testAdd(2);
+ status = sub->testAdd(11);
+ status = sub->testAdd(61);
+ status = sub->testAdd((1 * 3600) + 1);
+ status = sub->testAdd((2 * 3600) + 1);
// An "all" range, will pick up everything in the largest index.
- auto indexes = fake_event_module->getIndexes(0, 3 * 3600);
+ auto indexes = sub->getIndexes(0, 3 * 3600);
auto output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "3600.0, 3600.1, 3600.2");
// Restrict range to "most specific".
- indexes = fake_event_module->getIndexes(0, 5);
+ indexes = sub->getIndexes(0, 5);
output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "10.0");
// Get a mix of indexes for the lower bounding.
- indexes = fake_event_module->getIndexes(2, (3 * 3600));
+ indexes = sub->getIndexes(2, (3 * 3600));
output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "3600.1, 3600.2, 60.1, 10.0, 10.1");
// Rare, but test ONLY intermediate indexes.
- indexes = fake_event_module->getIndexes(2, (3 * 3600), 1);
+ indexes = sub->getIndexes(2, (3 * 3600), 1);
output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "60.0, 60.1, 60.60, 60.120");
// Add specific indexes to the upper bound.
- status = fake_event_module->testAdd((2 * 3600) + 11);
- status = fake_event_module->testAdd((2 * 3600) + 61);
- indexes = fake_event_module->getIndexes(2 * 3600, (2 * 3600) + 62);
+ status = sub->testAdd((2 * 3600) + 11);
+ status = sub->testAdd((2 * 3600) + 61);
+ indexes = sub->getIndexes(2 * 3600, (2 * 3600) + 62);
output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "60.120, 10.726");
// Request specific lower and upper bounding.
- indexes = fake_event_module->getIndexes(2, (2 * 3600) + 62);
+ indexes = sub->getIndexes(2, (2 * 3600) + 62);
output = boost::algorithm::join(indexes, ", ");
EXPECT_EQ(output, "3600.1, 60.1, 60.120, 10.0, 10.1, 10.726");
}
TEST_F(EventsDatabaseTests, test_record_range) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
+ auto sub = std::make_shared<FakeEventSubscriber>();
// Search within a specific record range.
- auto indexes = fake_event_module->getIndexes(0, 10);
- auto records = fake_event_module->getRecords(indexes);
+ auto indexes = sub->getIndexes(0, 10);
+ auto records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 2); // 1, 2
// Search within a large bound.
- indexes = fake_event_module->getIndexes(3, 3601);
+ indexes = sub->getIndexes(3, 3601);
// This will include the 0-10 bucket meaning 1, 2 will show up.
- records = fake_event_module->getRecords(indexes);
+ records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 5); // 1, 2, 11, 61, 3601
// Get all of the records.
- indexes = fake_event_module->getIndexes(0, 3 * 3600);
- records = fake_event_module->getRecords(indexes);
+ indexes = sub->getIndexes(0, 3 * 3600);
+ records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 8); // 1, 2, 11, 61, 3601, 7201, 7211, 7261
// stop = 0 is an alias for everything.
- indexes = fake_event_module->getIndexes(0, 0);
- records = fake_event_module->getRecords(indexes);
+ indexes = sub->getIndexes(0, 0);
+ records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 8);
}
TEST_F(EventsDatabaseTests, test_record_expiration) {
- auto fake_event_module = FakeEventSubscriber::getInstance();
+ auto sub = std::make_shared<FakeEventSubscriber>();
// No expiration
- auto indexes = fake_event_module->getIndexes(0, 60);
- auto records = fake_event_module->getRecords(indexes);
+ auto indexes = sub->getIndexes(0, 60);
+ auto records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 3); // 1, 2, 11
- fake_event_module->expire_events_ = true;
- fake_event_module->expire_time_ = 10;
- indexes = fake_event_module->getIndexes(0, 60);
- records = fake_event_module->getRecords(indexes);
+ sub->expire_events_ = true;
+ sub->expire_time_ = 10;
+ indexes = sub->getIndexes(0, 60);
+ records = sub->getRecords(indexes);
EXPECT_EQ(records.size(), 1); // 11
}
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
- boost::filesystem::remove_all(kTestingEventsDBPath);
+ boost::filesystem::remove_all(osquery::kTestingEventsDBPath);
return status;
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <typeinfo>
+
+#include <boost/filesystem/operations.hpp>
#include <gtest/gtest.h>
namespace osquery {
-class EventsTests : public testing::Test {
+const std::string kTestingEventsDBPath = "/tmp/rocksdb-osquery-testevents";
+
+class EventsTests : public ::testing::Test {
public:
+ void SetUp() {
+ // Setup a testing DB instance
+ DBHandle::getInstanceAtPath(kTestingEventsDBPath);
+ }
+
void TearDown() { EventFactory::deregisterEventPublishers(); }
};
-class BasicEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(BasicEventPublisher,
- SubscriptionContext,
- EventContext);
+// The most basic event publisher uses useless Subscription/Event.
+class BasicEventPublisher
+ : public EventPublisher<SubscriptionContext, EventContext> {};
+class AnotherBasicEventPublisher
+ : public EventPublisher<SubscriptionContext, EventContext> {};
+
+// Create some semi-useless subscription and event structures.
+struct FakeSubscriptionContext : SubscriptionContext {
+ int require_this_value;
+};
+struct FakeEventContext : EventContext {
+ int required_value;
+};
+
+// Typdef the shared_ptr accessors.
+typedef std::shared_ptr<FakeSubscriptionContext> FakeSubscriptionContextRef;
+typedef std::shared_ptr<FakeEventContext> FakeEventContextRef;
+
+// Now a publisher with a type.
+class FakeEventPublisher
+ : public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
+ DECLARE_PUBLISHER("FakePublisher");
};
-class FakeBasicEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(FakeBasicEventPublisher,
- SubscriptionContext,
- EventContext);
+class AnotherFakeEventPublisher
+ : public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
+ DECLARE_PUBLISHER("AnotherFakePublisher");
};
-TEST_F(EventsTests, test_register_event_pub) {
- Status status;
+TEST_F(EventsTests, test_event_pub) {
+ auto pub = std::make_shared<FakeEventPublisher>();
+ EXPECT_EQ(pub->type(), "FakePublisher");
+ // Test type names.
+ auto pub_sub = pub->createSubscriptionContext();
+ EXPECT_EQ(typeid(FakeSubscriptionContext), typeid(*pub_sub));
+}
+
+TEST_F(EventsTests, test_register_event_pub) {
// A caller may register an event type using the class template.
- status = EventFactory::registerEventPublisher<BasicEventPublisher>();
+ // This template class is equivilent to the reinterpret casting target.
+ auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
+ EXPECT_TRUE(status.ok());
+
+ // This class is the SAME, there was no type override.
+ status = EventFactory::registerEventPublisher<AnotherBasicEventPublisher>();
+ EXPECT_FALSE(status.ok());
+
+ // This class is different but also uses different types!
+ status = EventFactory::registerEventPublisher<FakeEventPublisher>();
EXPECT_TRUE(status.ok());
// May also register the event_pub instance
- auto event_pub_instance = std::make_shared<FakeBasicEventPublisher>();
- status = EventFactory::registerEventPublisher(event_pub_instance);
+ auto pub = std::make_shared<AnotherFakeEventPublisher>();
+ status = EventFactory::registerEventPublisher<AnotherFakeEventPublisher>(pub);
EXPECT_TRUE(status.ok());
+}
- // May NOT register without subclassing, enforced at compile time.
+TEST_F(EventsTests, test_event_pub_types) {
+ auto pub = std::make_shared<FakeEventPublisher>();
+ EXPECT_EQ(pub->type(), "FakePublisher");
+
+ EventFactory::registerEventPublisher(pub);
+ auto pub2 = EventFactory::getEventPublisher("FakePublisher");
+ EXPECT_EQ(pub->type(), pub2->type());
}
TEST_F(EventsTests, test_create_event_pub) {
- Status status;
-
- status = EventFactory::registerEventPublisher<BasicEventPublisher>();
+ auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
EXPECT_TRUE(status.ok());
- // Do not register the same event type twice.
- status = EventFactory::registerEventPublisher<BasicEventPublisher>();
- EXPECT_FALSE(status.ok());
-
// Make sure only the first event type was recorded.
EXPECT_EQ(EventFactory::numEventPublishers(), 1);
}
TEST_F(EventsTests, test_create_subscription) {
- Status status;
-
EventFactory::registerEventPublisher<BasicEventPublisher>();
// Make sure a subscription cannot be added for a non-existent event type.
// Note: It normally would not make sense to create a blank subscription.
auto subscription = Subscription::create();
- status =
- EventFactory::addSubscription("FakeBasicEventPublisher", subscription);
+ auto status = EventFactory::addSubscription("FakePublisher", subscription);
EXPECT_FALSE(status.ok());
// In this case we can still add a blank subscription to an existing event
// type.
- status = EventFactory::addSubscription("BasicEventPublisher", subscription);
+ status = EventFactory::addSubscription("publisher", subscription);
EXPECT_TRUE(status.ok());
// Make sure the subscription is added.
- EXPECT_EQ(EventFactory::numSubscriptions("BasicEventPublisher"), 1);
+ EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 1);
}
TEST_F(EventsTests, test_multiple_subscriptions) {
EventFactory::registerEventPublisher<BasicEventPublisher>();
auto subscription = Subscription::create();
- status = EventFactory::addSubscription("BasicEventPublisher", subscription);
- status = EventFactory::addSubscription("BasicEventPublisher", subscription);
+ status = EventFactory::addSubscription("publisher", subscription);
+ status = EventFactory::addSubscription("publisher", subscription);
- EXPECT_EQ(EventFactory::numSubscriptions("BasicEventPublisher"), 2);
+ EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 2);
}
struct TestSubscriptionContext : public SubscriptionContext {
int smallest;
};
-class TestEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(TestEventPublisher,
- TestSubscriptionContext,
- EventContext);
+class TestEventPublisher
+ : public EventPublisher<TestSubscriptionContext, EventContext> {
+ DECLARE_PUBLISHER("TestPublisher");
public:
Status setUp() {
};
TEST_F(EventsTests, test_create_custom_event_pub) {
- Status status;
-
- status = EventFactory::registerEventPublisher<BasicEventPublisher>();
- auto test_event_pub = std::make_shared<TestEventPublisher>();
- status = EventFactory::registerEventPublisher(test_event_pub);
+ auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
+ auto pub = std::make_shared<TestEventPublisher>();
+ status = EventFactory::registerEventPublisher(pub);
// These event types have unique event type IDs
EXPECT_TRUE(status.ok());
EXPECT_EQ(EventFactory::numEventPublishers(), 2);
// Make sure the setUp function was called.
- EXPECT_EQ(test_event_pub->getTestValue(), 1);
+ EXPECT_EQ(pub->getTestValue(), 1);
}
TEST_F(EventsTests, test_custom_subscription) {
- Status status;
-
// Step 1, register event type
- auto event_pub = std::make_shared<TestEventPublisher>();
- status = EventFactory::registerEventPublisher(event_pub);
+ auto pub = std::make_shared<TestEventPublisher>();
+ auto status = EventFactory::registerEventPublisher(pub);
// Step 2, create and configure a subscription context
- auto subscription_context = std::make_shared<TestSubscriptionContext>();
- subscription_context->smallest = -1;
+ auto sc = std::make_shared<TestSubscriptionContext>();
+ sc->smallest = -1;
// Step 3, add the subscription to the event type
- status =
- EventFactory::addSubscription("TestEventPublisher", subscription_context);
+ status = EventFactory::addSubscription("TestPublisher", sc);
EXPECT_TRUE(status.ok());
- EXPECT_EQ(event_pub->numSubscriptions(), 1);
+ EXPECT_EQ(pub->numSubscriptions(), 1);
// The event type must run configure for each added subscription.
- EXPECT_TRUE(event_pub->configure_run);
- EXPECT_EQ(event_pub->getTestValue(), -1);
+ EXPECT_TRUE(pub->configure_run);
+ EXPECT_EQ(pub->getTestValue(), -1);
}
TEST_F(EventsTests, test_tear_down) {
- Status status;
-
- auto event_pub = std::make_shared<TestEventPublisher>();
- status = EventFactory::registerEventPublisher(event_pub);
+ auto pub = std::make_shared<TestEventPublisher>();
+ auto status = EventFactory::registerEventPublisher(pub);
// Make sure set up incremented the test value.
- EXPECT_EQ(event_pub->getTestValue(), 1);
+ EXPECT_EQ(pub->getTestValue(), 1);
- status = EventFactory::deregisterEventPublisher("TestEventPublisher");
+ status = EventFactory::deregisterEventPublisher("TestPublisher");
EXPECT_TRUE(status.ok());
// Make sure tear down inremented the test value.
- EXPECT_EQ(event_pub->getTestValue(), 2);
+ EXPECT_EQ(pub->getTestValue(), 2);
// Once more, now deregistering all event types.
- status = EventFactory::registerEventPublisher(event_pub);
- EXPECT_EQ(event_pub->getTestValue(), 3);
+ status = EventFactory::registerEventPublisher(pub);
+ EXPECT_EQ(pub->getTestValue(), 3);
status = EventFactory::deregisterEventPublishers();
EXPECT_TRUE(status.ok());
- EXPECT_EQ(event_pub->getTestValue(), 4);
+ EXPECT_EQ(pub->getTestValue(), 4);
// Make sure the factory state represented.
EXPECT_EQ(EventFactory::numEventPublishers(), 0);
static int kBellHathTolled = 0;
-Status TestTheeCallback(EventContextRef context, bool reserved) {
+Status TestTheeCallback(EventContextRef context) {
kBellHathTolled += 1;
return Status(0, "OK");
}
+class FakeEventSubscriber : public EventSubscriber<FakeEventPublisher> {
+ DECLARE_SUBSCRIBER("FakeSubscriber");
+
+ public:
+ bool bellHathTolled;
+ bool contextBellHathTolled;
+ bool shouldFireBethHathTolled;
+
+ FakeEventSubscriber() {
+ bellHathTolled = false;
+ contextBellHathTolled = false;
+ shouldFireBethHathTolled = false;
+ }
+
+ Status Callback(const EventContextRef& ec) {
+ // We don't care about the subscription or the event contexts.
+ bellHathTolled = true;
+ return Status(0, "OK");
+ }
+
+ Status SpecialCallback(const FakeEventContextRef& ec) {
+ // Now we care that the event context is corrected passed.
+ if (ec->required_value == 42) {
+ contextBellHathTolled = true;
+ }
+ return Status(0, "OK");
+ }
+
+ void lateInit() {
+ auto sub_ctx = createSubscriptionContext();
+ subscribe(&FakeEventSubscriber::Callback, sub_ctx);
+ }
+
+ void laterInit() {
+ auto sub_ctx = createSubscriptionContext();
+ sub_ctx->require_this_value = 42;
+ subscribe(&FakeEventSubscriber::SpecialCallback, sub_ctx);
+ }
+};
+
+TEST_F(EventsTests, test_event_sub) {
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ EXPECT_EQ(sub->type(), "FakePublisher");
+ EXPECT_EQ(sub->name(), "FakeSubscriber");
+}
+
+TEST_F(EventsTests, test_event_sub_subscribe) {
+ auto pub = std::make_shared<FakeEventPublisher>();
+ EventFactory::registerEventPublisher(pub);
+
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ EventFactory::registerEventSubscriber(sub);
+
+ // Don't overload the normal `init` Subscription member.
+ sub->lateInit();
+ EXPECT_EQ(pub->numSubscriptions(), 1);
+
+ auto ec = pub->createEventContext();
+ pub->fire(ec, 0);
+
+ EXPECT_TRUE(sub->bellHathTolled);
+}
+
+TEST_F(EventsTests, test_event_sub_context) {
+ auto pub = std::make_shared<FakeEventPublisher>();
+ EventFactory::registerEventPublisher(pub);
+
+ auto sub = std::make_shared<FakeEventSubscriber>();
+ EventFactory::registerEventSubscriber(sub);
+
+ sub->laterInit();
+ auto ec = pub->createEventContext();
+ ec->required_value = 42;
+ pub->fire(ec, 0);
+
+ EXPECT_TRUE(sub->contextBellHathTolled);
+}
+
TEST_F(EventsTests, test_fire_event) {
Status status;
- auto event_pub = std::make_shared<BasicEventPublisher>();
- status = EventFactory::registerEventPublisher(event_pub);
+ auto pub = std::make_shared<BasicEventPublisher>();
+ status = EventFactory::registerEventPublisher(pub);
auto subscription = Subscription::create();
subscription->callback = TestTheeCallback;
- status = EventFactory::addSubscription("BasicEventPublisher", subscription);
+ status = EventFactory::addSubscription("publisher", subscription);
// The event context creation would normally happen in the event type.
- auto ec = event_pub->createEventContext();
- event_pub->fire(ec, 0);
+ auto ec = pub->createEventContext();
+ pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 1);
auto second_subscription = Subscription::create();
- status =
- EventFactory::addSubscription("BasicEventPublisher", second_subscription);
+ status = EventFactory::addSubscription("publisher", second_subscription);
// Now there are two subscriptions (one sans callback).
- event_pub->fire(ec, 0);
+ pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 2);
// Now both subscriptions have callbacks.
second_subscription->callback = TestTheeCallback;
- event_pub->fire(ec, 0);
+ pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 4);
}
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ int status = RUN_ALL_TESTS();
+ boost::filesystem::remove_all(osquery::kTestingEventsDBPath);
+ return status;
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <sstream>
#include <linux/limits.h>
-#include <glog/logging.h>
-
#include <osquery/events.h>
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
#include "osquery/events/linux/inotify.h"
// A file was moved to replace the watched path.
removeMonitor(event->wd, false);
} else {
- auto ec = createEventContext(event);
+ auto ec = createEventContextFrom(event);
fire(ec);
}
// Continue to iterate
return Status(0, "Continue");
}
-INotifyEventContextRef INotifyEventPublisher::createEventContext(
+INotifyEventContextRef INotifyEventPublisher::createEventContextFrom(
struct inotify_event* event) {
auto shared_event = std::make_shared<struct inotify_event>(*event);
auto ec = createEventContext();
return ec;
}
-bool INotifyEventPublisher::shouldFire(const INotifySubscriptionContextRef sc,
- const INotifyEventContextRef ec) {
+bool INotifyEventPublisher::shouldFire(const INotifySubscriptionContextRef& sc,
+ const INotifyEventContextRef& ec) {
if (!sc->recursive && sc->path != ec->path) {
// Monitored path is not recursive and path is not an exact match.
return false;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
*
* @param action The string action, a value in kMaskAction%s.
*/
- void requireAction(std::string action) {
+ void requireAction(const std::string& action) {
for (const auto& bit : kMaskActions) {
if (action == bit.second) {
mask = mask | bit.first;
* Uses INotifySubscriptionContext and INotifyEventContext for subscriptioning,
*eventing.
*/
-class INotifyEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(INotifyEventPublisher,
- INotifySubscriptionContext,
- INotifyEventContext);
+class INotifyEventPublisher
+ : public EventPublisher<INotifySubscriptionContext, INotifyEventContext> {
+ DECLARE_PUBLISHER("INotifyEventPublisher");
public:
/// Create an `inotify` handle descriptor.
bool isHandleOpen() { return inotify_handle_ > 0; }
private:
- INotifyEventContextRef createEventContext(struct inotify_event* event);
+ INotifyEventContextRef createEventContextFrom(struct inotify_event* event);
/// Check all added Subscription%s for a path.
bool isPathMonitored(const std::string& path);
/// Add an INotify watch (monitor) on this path.
bool removeMonitor(const std::string& path, bool force = false);
bool removeMonitor(int watch, bool force = false);
/// Given a SubscriptionContext and INotifyEventContext match path and action.
- bool shouldFire(const INotifySubscriptionContextRef mc,
- const INotifyEventContextRef ec);
+ bool shouldFire(const INotifySubscriptionContextRef& mc,
+ const INotifyEventContextRef& ec);
/// Get the INotify file descriptor.
int getHandle() { return inotify_handle_; }
/// Get the number of actual INotify active descriptors.
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <stdio.h>
EventFactory::end(false);
}
-class TestINotifyEventSubscriber : public EventSubscriber {
- DECLARE_EVENTSUBSCRIBER(TestINotifyEventSubscriber, INotifyEventPublisher);
- DECLARE_CALLBACK(SimpleCallback, INotifyEventContext);
- DECLARE_CALLBACK(Callback, INotifyEventContext);
+class TestINotifyEventSubscriber
+ : public EventSubscriber<INotifyEventPublisher> {
+ DECLARE_SUBSCRIBER("TestINotifyEventSubscriber");
public:
void init() { callback_count_ = 0; }
- Status SimpleCallback(const INotifyEventContextRef ec) {
+ Status SimpleCallback(const INotifyEventContextRef& ec) {
callback_count_ += 1;
return Status(0, "OK");
}
- Status Callback(const INotifyEventContextRef ec) {
- Row r;
- r["action"] = ec->action;
- r["path"] = ec->path;
+ Status Callback(const INotifyEventContextRef& ec) {
+ // The following comments are an example Callback routine.
+ // Row r;
+ // r["action"] = ec->action;
+ // r["path"] = ec->path;
// Normally would call Add here.
actions_.push_back(ec->action);
return Status(0, "OK");
}
- static void WaitForEvents(int max, int num_events = 1) {
+ SCRef GetSubscription(const std::string& path, uint32_t mask = 0) {
+ auto mc = createSubscriptionContext();
+ mc->path = path;
+ mc->mask = mask;
+ return mc;
+ }
+
+ void WaitForEvents(int max, int num_events = 1) {
int delay = 0;
while (delay < max * 1000) {
- if (getInstance()->callback_count_ >= num_events) {
+ if (callback_count_ >= num_events) {
return;
}
::usleep(50);
}
}
- static std::vector<std::string> actions() { return getInstance()->actions_; }
+ std::vector<std::string> actions() { return actions_; }
- static int count() { return getInstance()->callback_count_; }
+ int count() { return callback_count_; }
public:
int callback_count_;
TEST_F(INotifyTests, test_inotify_fire_event) {
// Assume event type is registered.
StartEventLoop();
- TestINotifyEventSubscriber::getInstance()->init();
+ auto sub = std::make_shared<TestINotifyEventSubscriber>();
+ sub->init();
// Create a subscriptioning context, note the added Event to the symbol
- SubscriptionAction(
- kRealTestPath, 0, TestINotifyEventSubscriber::EventSimpleCallback);
- TriggerEvent(kRealTestPath);
+ auto sc = sub->GetSubscription(kRealTestPath, 0);
+ sub->subscribe(&TestINotifyEventSubscriber::SimpleCallback, sc);
- TestINotifyEventSubscriber::WaitForEvents(kMaxEventLatency);
+ TriggerEvent(kRealTestPath);
+ sub->WaitForEvents(kMaxEventLatency);
// Make sure our expected event fired (aka subscription callback was called).
- EXPECT_TRUE(TestINotifyEventSubscriber::count() > 0);
+ EXPECT_TRUE(sub->count() > 0);
// Cause the thread to tear down.
EndEventLoop();
TEST_F(INotifyTests, test_inotify_event_action) {
// Assume event type is registered.
StartEventLoop();
- TestINotifyEventSubscriber::getInstance()->init();
+ auto sub = std::make_shared<TestINotifyEventSubscriber>();
+ sub->init();
- SubscriptionAction(
- kRealTestPath, 0, TestINotifyEventSubscriber::EventCallback);
- TriggerEvent(kRealTestPath);
+ auto sc = sub->GetSubscription(kRealTestPath, 0);
+ sub->subscribe(&TestINotifyEventSubscriber::Callback, sc);
- TestINotifyEventSubscriber::WaitForEvents(kMaxEventLatency, 1);
+ TriggerEvent(kRealTestPath);
+ sub->WaitForEvents(kMaxEventLatency, 1);
// Make sure the inotify action was expected.
- EXPECT_TRUE(TestINotifyEventSubscriber::actions().size() > 0);
- EXPECT_EQ(TestINotifyEventSubscriber::actions()[0], "UPDATED");
+ EXPECT_TRUE(sub->actions().size() > 0);
+ EXPECT_EQ(sub->actions()[0], "UPDATED");
// Cause the thread to tear down.
EndEventLoop();
TEST_F(INotifyTests, test_inotify_recursion) {
StartEventLoop();
- TestINotifyEventSubscriber::getInstance()->init();
+
+ auto sub = std::make_shared<TestINotifyEventSubscriber>();
+ sub->init();
boost::filesystem::create_directory(kRealTestDir);
boost::filesystem::create_directory(kRealTestSubDir);
// Subscribe to the directory inode
- auto mc = std::make_shared<INotifySubscriptionContext>();
+ auto mc = sub->createSubscriptionContext();
mc->path = kRealTestDir;
mc->recursive = true;
+ sub->subscribe(&TestINotifyEventSubscriber::Callback, mc);
- EventFactory::addSubscription(
- "INotifyEventPublisher", mc, TestINotifyEventSubscriber::EventCallback);
// Trigger on a subdirectory's file.
TriggerEvent(kRealTestSubDirPath);
- TestINotifyEventSubscriber::WaitForEvents(kMaxEventLatency, 1);
- EXPECT_TRUE(TestINotifyEventSubscriber::count() > 0);
+ sub->WaitForEvents(kMaxEventLatency, 1);
+ EXPECT_TRUE(sub->count() > 0);
EndEventLoop();
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <osquery/events.h>
#include <osquery/filesystem.h>
return Status(1, "udev monitor failed.");
}
- auto ec = createEventContext(device);
+ auto ec = createEventContextFrom(device);
fire(ec);
udev_device_unref(device);
std::string UdevEventPublisher::getValue(struct udev_device* device,
const std::string& property) {
- auto value = udev_device_get_property_value(
- device, std::string("ID_" + property).c_str());
+ auto value = udev_device_get_property_value(device, property.c_str());
if (value != nullptr) {
return std::string(value);
}
return "";
}
-UdevEventContextRef UdevEventPublisher::createEventContext(
+std::string UdevEventPublisher::getAttr(struct udev_device* device,
+ const std::string& attr) {
+ auto value = udev_device_get_sysattr_value(device, attr.c_str());
+ if (value != nullptr) {
+ return std::string(value);
+ }
+ return "";
+}
+
+UdevEventContextRef UdevEventPublisher::createEventContextFrom(
struct udev_device* device) {
auto ec = createEventContext();
ec->device = device;
return ec;
}
-bool UdevEventPublisher::shouldFire(const UdevSubscriptionContextRef sc,
- const UdevEventContextRef ec) {
+bool UdevEventPublisher::shouldFire(const UdevSubscriptionContextRef& sc,
+ const UdevEventContextRef& ec) {
if (sc->action != UDEV_EVENT_ACTION_ALL) {
if (sc->action != ec->action) {
return false;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
* @brief A Linux `udev` EventPublisher.
*
*/
-class UdevEventPublisher : public EventPublisher {
- DECLARE_EVENTPUBLISHER(UdevEventPublisher,
- UdevSubscriptionContext,
- UdevEventContext);
+class UdevEventPublisher
+ : public EventPublisher<UdevSubscriptionContext, UdevEventContext> {
+ DECLARE_PUBLISHER("UdevEventPublisher");
public:
Status setUp();
Status run();
- UdevEventPublisher() : EventPublisher() { handle_ = nullptr; }
+ UdevEventPublisher() : EventPublisher() {
+ handle_ = nullptr;
+ monitor_ = nullptr;
+ }
/**
* @brief Return a string representation of a udev property.
*
* @param device the udev device pointer.
- * @param property the udev property without the "ID_" prefix.
+ * @param property the udev property identifier string.
* @return string representation of the property or empty if null.
*/
static std::string getValue(struct udev_device* device,
const std::string& property);
+ /**
+ * @brief Return a string representation of a udev system attribute.
+ *
+ * @param device the udev device pointer.
+ * @param property the udev system attribute identifier string.
+ * @return string representation of the attribute or empty if null.
+ */
+ static std::string getAttr(struct udev_device* device,
+ const std::string& attr);
+
private:
/// udev handle (socket descriptor contained within).
struct udev *handle_;
private:
/// Check subscription details.
- bool shouldFire(const UdevSubscriptionContextRef mc,
- const UdevEventContextRef ec);
+ bool shouldFire(const UdevSubscriptionContextRef& mc,
+ const UdevEventContextRef& ec);
/// Helper function to create an EventContext using a udev_device pointer.
- UdevEventContextRef createEventContext(struct udev_device* device);
+ UdevEventContextRef createEventContextFrom(struct udev_device* device);
};
}
ADD_OSQUERY_LIBRARY(osquery_filesystem filesystem.cpp)
-ADD_OSQUERY_LIBRARY(osquery_filesystem_linux linux/proc.cpp)
+ADD_OSQUERY_LIBRARY(osquery_filesystem_linux linux/proc.cpp
+ linux/mem.cpp)
ADD_OSQUERY_TEST(osquery_filesystem_tests filesystem_tests.cpp)
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <exception>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
-#include <glog/logging.h>
-
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
namespace pt = boost::property_tree;
namespace fs = boost::filesystem;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
-#include <osquery/filesystem.h>
#include <fstream>
#include <stdio.h>
+#include <gtest/gtest.h>
+
#include <boost/property_tree/ptree.hpp>
-#include <gtest/gtest.h>
-#include <glog/logging.h>
+#include <osquery/filesystem.h>
+#include <osquery/logger.h>
namespace pt = boost::property_tree;
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <osquery/filesystem.h>
+#include <osquery/flags.h>
+#include <osquery/logger.h>
+
+namespace osquery {
+
+#define kLinuxMaxMemRead 0x10000
+
+const std::string kLinuxMemPath = "/dev/mem";
+
+DEFINE_osquery_flag(bool,
+ disable_memory,
+ false,
+ "Disable physical memory reads.");
+
+Status readMem(int fd, size_t base, size_t length, uint8_t* buffer) {
+ if (lseek(fd, base, SEEK_SET) == -1) {
+ return Status(1, "Cannot seek to physical base");
+ }
+
+ // Read from raw memory until an unrecoverable read error or the all of the
+ // requested bytes are read.
+ size_t total_read = 0;
+ size_t bytes_read = 0;
+ while (total_read != length && bytes_read != 0) {
+ bytes_read = read(fd, buffer + total_read, length - total_read);
+ if (bytes_read == -1) {
+ if (errno != EINTR) {
+ return Status(1, "Cannot read requested length");
+ }
+ } else {
+ total_read += bytes_read;
+ }
+ }
+
+ // The read call finished without reading the requested number of bytes.
+ if (total_read != length) {
+ return Status(1, "Read incorrect number of bytes");
+ }
+
+ return Status(0, "OK");
+}
+
+Status readRawMem(size_t base, size_t length, void** buffer) {
+ *buffer = 0;
+
+ if (FLAGS_disable_memory) {
+ return Status(1, "Configuration has disabled physical memory reads");
+ }
+
+ if (length > kLinuxMaxMemRead) {
+ return Status(1, "Cowardly refusing to read a large number of bytes");
+ }
+
+ auto status = isReadable(kLinuxMemPath);
+ if (!status.ok()) {
+ // For non-su users *hopefully* raw memory is not readable.
+ return status;
+ }
+
+ int fd = open(kLinuxMemPath.c_str(), O_RDONLY);
+ if (fd < 0) {
+ return Status(1, std::string("Cannot open ") + kLinuxMemPath);
+ }
+
+ if ((*buffer = malloc(length)) == nullptr) {
+ close(fd);
+ return Status(1, "Cannot allocate memory for read");
+ }
+
+#ifdef _SC_PAGESIZE
+ size_t offset = base % sysconf(_SC_PAGESIZE);
+#else
+ // getpagesize() is more or less deprecated.
+ size_t offset = base % getpagesize();
+#endif
+
+ // Use memmap for maximum portability over read().
+ auto map = mmap(0, offset + length, PROT_READ, MAP_SHARED, fd, base - offset);
+ if (map == MAP_FAILED) {
+ // Could fallback to a lseek/read.
+ if (!readMem(fd, base, length, (uint8_t*)*buffer).ok()) {
+ close(fd);
+ free(*buffer);
+ return Status(1, "Cannot memory map or seek/read memory");
+ }
+ } else {
+ // Memory map succeeded, copy and unmap.
+ memcpy(*buffer, (uint8_t*)map + offset, length);
+ if (munmap(map, offset + length) == -1) {
+ LOG(WARNING) << "Unable to unmap raw memory";
+ }
+ }
+
+ close(fd);
+ return Status(0, "OK");
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <exception>
+#include <map>
+#include <vector>
#include <unistd.h>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
-#include <glog/logging.h>
-
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
namespace osquery {
}
Status procDescriptors(const std::string& process,
- std::vector<std::string>& descriptors) {
+ std::map<std::string, std::string>& descriptors) {
auto descriptors_path = kLinuxProcPath + "/" + process + "/fd";
try {
// Access to the process' /fd may be restricted.
boost::filesystem::directory_iterator it(descriptors_path), end;
for (; it != end; ++it) {
- descriptors.push_back(it->path().leaf().string());
+ auto fd = it->path().leaf().string();
+ std::string linkname;
+ if (procReadDescriptor(process, fd, linkname).ok()) {
+ descriptors[fd] = linkname;
+ }
}
} catch (boost::filesystem::filesystem_error& e) {
return Status(1, "Cannot access descriptors for " + process);
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <algorithm>
#include <thread>
-#include <glog/logging.h>
-
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/logger/plugin.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <glog/logging.h>
#include <osquery/core.h>
#include <osquery/logger.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <exception>
#include <mutex>
-#include <glog/logging.h>
-
#include <osquery/filesystem.h>
#include <osquery/flags.h>
+#include <osquery/logger.h>
#include <osquery/logger/plugin.h>
using osquery::Status;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <boost/thread.hpp>
-#include <glog/logging.h>
-
#include <osquery/config.h>
#include <osquery/config/plugin.h>
#include <osquery/core.h>
#include <osquery/database.h>
#include <osquery/events.h>
+#include <osquery/logger.h>
#include <osquery/logger/plugin.h>
#include <osquery/scheduler.h>
+#ifndef __APPLE__
+namespace osquery {
+DEFINE_osquery_flag(bool, daemonize, false, "Run as daemon (osqueryd only).");
+}
+#endif
+
+namespace osquery {
+DEFINE_osquery_flag(bool,
+ config_check,
+ false,
+ "Check the format and accessibility of the daemon");
+}
+
int main(int argc, char* argv[]) {
osquery::initOsquery(argc, argv, osquery::OSQUERY_TOOL_DAEMON);
+ if (osquery::FLAGS_config_check) {
+ auto s = osquery::Config::checkConfig();
+ if (!s.ok()) {
+ std::cerr << "Error reading config: " << s.toString() << "\n";
+ }
+ return s.getCode();
+ }
+
+#ifndef __APPLE__
+ // OSX uses launchd to daemonize.
+ if (osquery::FLAGS_daemonize) {
+ if (daemon(0, 0) == -1) {
+ ::exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
auto pid_status = osquery::createPidFile();
if (!pid_status.ok()) {
- LOG(ERROR) << "Could not create osquery pidfile: " << pid_status.toString();
+ LOG(ERROR) << "Could not start osqueryd: " << pid_status.toString();
::exit(EXIT_FAILURE);
}
osquery::DBHandle::getInstance();
} catch (std::exception& e) {
LOG(ERROR) << "osqueryd failed to start: " << e.what();
- ::exit(1);
+ ::exit(EXIT_FAILURE);
}
LOG(INFO) << "Listing all plugins";
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#include <string>
#include <osquery/core.h>
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <gflags/gflags.h>
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
+
+DEFINE_string(query, "", "query to execute");
+DEFINE_int32(iterations, 1, "times to run the query in question");
+DEFINE_int32(delay, 0, "delay before and after the query");
+
+int main(int argc, char* argv[]) {
+ osquery::initOsquery(argc, argv);
+
+ if (FLAGS_query != "") {
+ if (FLAGS_delay != 0) {
+ ::sleep(FLAGS_delay);
+ }
+
+ for (int i = 0; i < FLAGS_iterations; ++i) {
+ int err;
+ LOG(INFO) << "Executing: " << FLAGS_query;
+ osquery::query(FLAGS_query, err);
+ if (err != 0) {
+ LOG(ERROR) << "Query failed: " << err;
+ return 1;
+ }
+ LOG(INFO) << "Query succeeded";
+ }
+
+ if (FLAGS_delay != 0) {
+ ::sleep(FLAGS_delay);
+ }
+ } else {
+ LOG(ERROR) << "Usage: run --query=\"<query>\"";
+ return 1;
+ }
+
+ return 0;
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#include <osquery/core.h>
#include <osquery/database.h>
#include <osquery/devtools.h>
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#pragma once
#include <boost/noncopyable.hpp>
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#pragma once
#include <functional>
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <osquery/registry.h>
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#include <memory>
#include <string>
-#include <glog/logging.h>
#include <gtest/gtest.h>
+#include <osquery/logger.h>
+#include <osquery/registry.h>
+
class TestPlugin {
public:
virtual std::string getName() { return "test_base"; }
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#pragma once
namespace osquery {
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#include <climits>
#include <ctime>
-
-#include <glog/logging.h>
+#include <random>
#include <osquery/config.h>
#include <osquery/core.h>
"hostname",
"Field used to identify the host running osqueryd");
+DEFINE_osquery_flag(int32,
+ schedule_splay_percent,
+ 10,
+ "Percent to splay config times.");
+
Status getHostIdentifier(std::string& ident) {
std::shared_ptr<DBHandle> db;
try {
db = DBHandle::getInstance();
- } catch (const std::exception& e) {
+ } catch (const std::runtime_error& e) {
return Status(1, e.what());
}
}
}
+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();
+ }
+}
+
void launchQueries(const std::vector<OsqueryScheduledQuery>& queries,
const int64_t& second) {
for (const auto& q : queries) {
if (second % q.interval == 0) {
- LOG(INFO) << "Executing query: " << q.query;
- int unix_time = std::time(0);
- auto sql = SQL(q.query);
- if (!sql.ok()) {
- LOG(ERROR) << "Error executing query (" << q.query
- << "): " << sql.getMessageString();
- continue;
- }
- auto dbQuery = Query(q);
- 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.toString();
- continue;
- }
-
- if (diff_results.added.size() > 0 || diff_results.removed.size() > 0) {
- ScheduledQueryLogItem item;
- Status s;
-
- item.diffResults = diff_results;
- item.name = q.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 " << q.name
- << " for host: " << ident;
- s = logScheduledQueryLogItem(item);
- if (!s.ok()) {
- LOG(ERROR) << "Error logging the results of query \"" << q.query
- << "\""
- << ": " << s.toString();
- }
- }
+ launchQuery(q);
}
}
}
+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);
+}
+
void initializeScheduler() {
DLOG(INFO) << "osquery::initializeScheduler";
time_t t = time(0);
struct tm* local = localtime(&t);
unsigned long int second = local->tm_sec;
- auto cfg = Config::getInstance();
+
#ifdef OSQUERY_TEST_DAEMON
// if we're testing the daemon, only iterate through 15 "seconds"
static unsigned long int stop_at = second + 15;
// if this is production, count forever
static unsigned long int stop_at = ULONG_MAX;
#endif
+
+ auto cfg = Config::getInstance();
+
+ // Iterate over scheduled queryies and add a splay to each.
+ auto schedule = cfg->getScheduledQueries();
+ 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;
+ }
+
for (; second <= stop_at; ++second) {
- launchQueries(cfg->getScheduledQueries(), second);
- sleep(1);
+ launchQueries(schedule, second);
+ ::sleep(1);
}
}
}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#include <gtest/gtest.h>
#include <osquery/scheduler.h>
+namespace osquery {
+
class SchedulerTests : public testing::Test {};
TEST_F(SchedulerTests, test) { EXPECT_EQ(true, true); }
+TEST_F(SchedulerTests, test_splay) {
+ auto val1 = splayValue(100, 10);
+ EXPECT_GE(val1, 90);
+ EXPECT_LE(val1, 110);
+
+ auto val2 = splayValue(100, 10);
+ EXPECT_GE(val2, 90);
+ EXPECT_LE(val2, 110);
+
+ auto val3 = splayValue(10, 0);
+ EXPECT_EQ(val3, 10);
+
+ auto val4 = splayValue(100, 1);
+ EXPECT_GE(val4, 99);
+ EXPECT_LE(val4, 101);
+
+ auto val5 = splayValue(1, 10);
+ EXPECT_EQ(val5, 1);
+}
+}
+
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
ADD_OSQUERY_LIBRARY(osquery_tables_linux events/linux/passwd_changes.cpp
events/linux/hardware_events.cpp
networking/linux/routes.cpp
- networking/linux/socket_inode.cpp
- networking/linux/port_inode.cpp
+ networking/linux/process_open_sockets.cpp
networking/linux/arp_cache.cpp
+ system/linux/acpi_tables.cpp
system/linux/kernel_modules.cpp
system/linux/processes.cpp
+ system/linux/process_open_files.cpp
+ system/linux/smbios_tables.cpp
system/linux/users.cpp
system/linux/groups.cpp
- system/linux/mounts.cpp)
+ system/linux/mounts.cpp
+ system/linux/pci_devices.cpp
+ system/linux/usb_devices.cpp)
ADD_OSQUERY_LIBRARY(osquery_tables networking/utils.cpp
networking/etc_hosts.cpp
+ networking/etc_services.cpp
+ networking/listening_ports.cpp
utility/time.cpp
- utility/crontab.cpp
utility/hash.cpp
utility/file.cpp
+ utility/osquery.cpp
+ system/crontab.cpp
+ system/smbios_utils.cpp
system/last.cpp
system/shell_history.cpp
system/suid_bin.cpp
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <vector>
#include <string>
/**
* @brief Track udev events in Linux
*/
-class HardwareEventSubscriber : public EventSubscriber {
- DECLARE_EVENTSUBSCRIBER(HardwareEventSubscriber, UdevEventPublisher);
- DECLARE_CALLBACK(Callback, UdevEventContext);
+class HardwareEventSubscriber : public EventSubscriber<UdevEventPublisher> {
+ DECLARE_SUBSCRIBER("HardwareEventSubscriber");
public:
void init();
- Status Callback(const UdevEventContextRef ec);
+ Status Callback(const UdevEventContextRef& ec);
};
REGISTER_EVENTSUBSCRIBER(HardwareEventSubscriber);
void HardwareEventSubscriber::init() {
- auto subscription = UdevEventPublisher::createSubscriptionContext();
+ auto subscription = createSubscriptionContext();
subscription->action = UDEV_EVENT_ACTION_ALL;
- BIND_CALLBACK(Callback, subscription);
+ subscribe(&HardwareEventSubscriber::Callback, subscription);
}
-Status HardwareEventSubscriber::Callback(const UdevEventContextRef ec) {
+Status HardwareEventSubscriber::Callback(const UdevEventContextRef& ec) {
Row r;
if (ec->devtype.empty()) {
r["driver"] = ec->driver;
// UDEV properties.
- r["model"] = UdevEventPublisher::getValue(device, "MODEL");
+ r["model"] = UdevEventPublisher::getValue(device, "ID_MODEL_FROM_DATABASE");
if (r["path"].empty() && r["model"].empty()) {
// Don't emit mising path/model combos.
return Status(0, "Missing path and model.");
}
- r["model_id"] = INTEGER(UdevEventPublisher::getValue(device, "MODEL_ID"));
- r["vendor"] = UdevEventPublisher::getValue(device, "VENDOR");
- r["vendor_id"] = INTEGER(UdevEventPublisher::getValue(device, "VENDOR_ID"));
- r["serial"] = INTEGER(UdevEventPublisher::getValue(device, "SERIAL_SHORT"));
- r["revision"] = INTEGER(UdevEventPublisher::getValue(device, "REVISION"));
+ r["model_id"] = INTEGER(UdevEventPublisher::getValue(device, "ID_MODEL_ID"));
+ r["vendor"] = UdevEventPublisher::getValue(device, "ID_VENDOR_FROM_DATABASE");
+ r["vendor_id"] =
+ INTEGER(UdevEventPublisher::getValue(device, "ID_VENDOR_ID"));
+ r["serial"] =
+ INTEGER(UdevEventPublisher::getValue(device, "ID_SERIAL_SHORT"));
+ r["revision"] = INTEGER(UdevEventPublisher::getValue(device, "ID_REVISION"));
r["time"] = INTEGER(ec->time);
add(r, ec->time);
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <vector>
#include <string>
-#include <glog/logging.h>
-
#include <osquery/core.h>
+#include <osquery/logger.h>
#include <osquery/tables.h>
+
#include "osquery/events/linux/inotify.h"
namespace osquery {
*
* This is mostly an example EventSubscriber implementation.
*/
-class PasswdChangesEventSubscriber : public EventSubscriber {
- DECLARE_EVENTSUBSCRIBER(PasswdChangesEventSubscriber, INotifyEventPublisher);
- DECLARE_CALLBACK(Callback, INotifyEventContext);
+class PasswdChangesEventSubscriber
+ : public EventSubscriber<INotifyEventPublisher> {
+ DECLARE_SUBSCRIBER("PasswdChangesEventSubscriber");
public:
void init();
*
* @return Was the callback successful.
*/
- Status Callback(const INotifyEventContextRef ec);
+ Status Callback(const INotifyEventContextRef& ec);
};
/**
REGISTER_EVENTSUBSCRIBER(PasswdChangesEventSubscriber);
void PasswdChangesEventSubscriber::init() {
- auto mc = INotifyEventPublisher::createSubscriptionContext();
+ auto mc = createSubscriptionContext();
mc->path = "/etc/passwd";
mc->mask = IN_ATTRIB | IN_MODIFY | IN_DELETE | IN_CREATE;
- BIND_CALLBACK(Callback, mc);
+ subscribe(&PasswdChangesEventSubscriber::Callback, mc);
}
-Status PasswdChangesEventSubscriber::Callback(const INotifyEventContextRef ec) {
+Status PasswdChangesEventSubscriber::Callback(
+ const INotifyEventContextRef& ec) {
Row r;
r["action"] = ec->action;
r["time"] = ec->time_string;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <vector>
#include <string>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>
-#include <glog/logging.h>
-
#include <osquery/core.h>
-#include <osquery/tables.h>
#include <osquery/filesystem.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
namespace osquery {
namespace tables {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <gtest/gtest.h>
-#include <glog/logging.h>
-#include "osquery/core/test_util.h"
+#include <osquery/logger.h>
#include <osquery/database.h>
-using namespace osquery::core;
+#include "osquery/core/test_util.h"
namespace osquery {
namespace tables {
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <vector>
+#include <string>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+#include <osquery/filesystem.h>
+
+namespace osquery {
+namespace tables {
+
+QueryData parseEtcServicesContent(const std::string& content) {
+ QueryData results;
+
+ for (const auto& line : split(content, "\n")) {
+ // Empty line or comment.
+ if (line.size() == 0 || boost::starts_with(line, "#")) {
+ continue;
+ }
+
+ // [0]: name port/protocol [aliases]
+ // [1]: [comment part1]
+ // [2]: [comment part2]
+ // [n]: [comment partn]
+ auto service_info_comment = split(line, "#");
+
+ // [0]: name
+ // [1]: port/protocol
+ // [2]: [aliases0]
+ // [3]: [aliases1]
+ // [n]: [aliasesn]
+ auto service_info = split(service_info_comment[0]);
+ if (service_info.size() < 2) {
+ LOG(WARNING) << "Line of /etc/services wasn't properly formatted. "
+ << "Expected at least 2, got " << service_info.size();
+ continue;
+ }
+
+ // [0]: port [1]: protocol
+ auto service_port_protocol = split(service_info[1], "/");
+ if (service_port_protocol.size() != 2) {
+ LOG(WARNING) << "Line of /etc/services wasn't properly formatted. "
+ << "Expected 2, got " << service_port_protocol.size();
+ continue;
+ }
+
+ Row r;
+ r["name"] = TEXT(service_info[0]);
+ r["port"] = INTEGER(service_port_protocol[0]);
+ r["protocol"] = TEXT(service_port_protocol[1]);
+
+ // Removes the name and the port/protcol elements.
+ service_info.erase(service_info.begin(), service_info.begin() + 2);
+ r["aliases"] = TEXT(boost::algorithm::join(service_info, " "));
+
+ // If there is a comment for the service.
+ if (service_info_comment.size() > 1) {
+ // Removes everything except the comment (parts of the comment).
+ service_info_comment.erase(service_info_comment.begin(), service_info_comment.begin() + 1);
+ r["comment"] = TEXT(boost::algorithm::join(service_info_comment, " # "));
+ }
+ results.push_back(r);
+ }
+ return results;
+}
+
+QueryData genEtcServices(QueryContext& context) {
+ std::string content;
+ auto s = osquery::readFile("/etc/services", content);
+ if (s.ok()) {
+ return parseEtcServicesContent(content);
+ } else {
+ LOG(ERROR) << "Error reading /etc/services: " << s.toString();
+ return {};
+ }
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <fstream>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
#ifndef _UAPI_INET_DIAG_H_
#define _UAPI_INET_DIAG_H_
+++ /dev/null
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <exception>
-
-#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/tcp.h>
-#include <netinet/in.h>
-
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <glog/logging.h>
-
-#include <osquery/core.h>
-#include <osquery/tables.h>
-
-// From uapi/linux/sock_diag.h
-// From linux/sock_diag.h (<= 3.6)
-#ifndef SOCK_DIAG_BY_FAMILY
-#define SOCK_DIAG_BY_FAMILY 20
-#endif
-
-#include "inet_diag.h"
-
-namespace osquery {
-namespace tables {
-
-// heavily influenced by github.com/kristrev/inet-diag-example
-enum {
- TCP_ESTABLISHED = 1,
- TCP_SYN_SENT,
- TCP_SYN_RECV,
- TCP_FIN_WAIT1,
- TCP_FIN_WAIT2,
- TCP_TIME_WAIT,
- TCP_CLOSE,
- TCP_CLOSE_WAIT,
- TCP_LAST_ACK,
- TCP_LISTEN,
- TCP_CLOSING
-};
-
-#define TCPF_ALL 0xFFF
-#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
-
-int send_diag_msg(int sockfd, int family) {
- struct msghdr msg;
- struct nlmsghdr nlh;
- struct inet_diag_req_v2 conn_req;
- struct sockaddr_nl sa;
- struct iovec iov[4];
- int retval = 0;
-
- memset(&msg, 0, sizeof(msg));
- memset(&sa, 0, sizeof(sa));
- memset(&nlh, 0, sizeof(nlh));
- memset(&conn_req, 0, sizeof(conn_req));
-
- sa.nl_family = AF_NETLINK;
-
- conn_req.sdiag_family = family;
- conn_req.sdiag_protocol = IPPROTO_TCP;
-
- conn_req.idiag_states = TCPF_ALL & ~((1 << TCP_SYN_RECV) |
- (1 << TCP_TIME_WAIT) | (1 << TCP_CLOSE));
-
- conn_req.idiag_ext |= (1 << (INET_DIAG_INFO - 1));
-
- nlh.nlmsg_len = NLMSG_LENGTH(sizeof(conn_req));
- nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
-
- nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
- iov[0].iov_base = (void *)&nlh;
- iov[0].iov_len = sizeof(nlh);
- iov[1].iov_base = (void *)&conn_req;
- iov[1].iov_len = sizeof(conn_req);
-
- msg.msg_name = (void *)&sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = iov;
- msg.msg_iovlen = 2;
-
- retval = sendmsg(sockfd, &msg, 0);
-
- return retval;
-}
-
-Row parse_diag_msg(struct inet_diag_msg *diag_msg, int rtalen, int family) {
- char local_addr_buf[INET6_ADDRSTRLEN];
- char remote_addr_buf[INET6_ADDRSTRLEN];
-
- memset(local_addr_buf, 0, sizeof(local_addr_buf));
- memset(remote_addr_buf, 0, sizeof(remote_addr_buf));
-
- // set up data structures depending on idiag_family type
- if (diag_msg->idiag_family == AF_INET) {
- inet_ntop(AF_INET,
- (struct in_addr *)&(diag_msg->id.idiag_src),
- local_addr_buf,
- INET_ADDRSTRLEN);
- inet_ntop(AF_INET,
- (struct in_addr *)&(diag_msg->id.idiag_dst),
- remote_addr_buf,
- INET_ADDRSTRLEN);
- } else if (diag_msg->idiag_family == AF_INET6) {
- inet_ntop(AF_INET6,
- (struct in_addr6 *)&(diag_msg->id.idiag_src),
- local_addr_buf,
- INET6_ADDRSTRLEN);
- inet_ntop(AF_INET6,
- (struct in_addr6 *)&(diag_msg->id.idiag_dst),
- remote_addr_buf,
- INET6_ADDRSTRLEN);
- }
-
- // populate the Row from diag_msg fields
- Row row;
- row["inode"] = INTEGER(diag_msg->idiag_inode);
- row["local_port"] = INTEGER(ntohs(diag_msg->id.idiag_sport));
- row["remote_port"] = INTEGER(ntohs(diag_msg->id.idiag_dport));
- row["local_ip"] = TEXT(local_addr_buf);
- row["remote_ip"] = TEXT(remote_addr_buf);
- row["family"] = INTEGER(family);
- return row;
-}
-
-void getPortInode(QueryData &results, int family) {
- int nl_sock = 0;
- int numbytes = 0;
- int rtalen = 0;
- struct nlmsghdr *nlh;
- uint8_t recv_buf[SOCKET_BUFFER_SIZE];
- struct inet_diag_msg *diag_msg;
-
- // set up the socket
- if ((nl_sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) {
- close(nl_sock);
- return;
- }
-
- // send the inet_diag message
- if (send_diag_msg(nl_sock, family) < 0) {
- close(nl_sock);
- return;
- }
-
- // recieve netlink messages
- numbytes = recv(nl_sock, recv_buf, sizeof(recv_buf), 0);
- nlh = (struct nlmsghdr *)recv_buf;
- while (NLMSG_OK(nlh, numbytes)) {
-
- // close the socket once NLMSG_DONE header recieved
- if (nlh->nlmsg_type == NLMSG_DONE) {
- close(nl_sock);
- return;
- }
-
- if (nlh->nlmsg_type == NLMSG_ERROR) {
- close(nl_sock);
- return;
- }
-
- // parse and process netlink message
- diag_msg = (struct inet_diag_msg *)NLMSG_DATA(nlh);
- rtalen = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*diag_msg));
- try {
- results.push_back(parse_diag_msg(diag_msg, rtalen, family));
- } catch (std::exception &e) {
- LOG(ERROR) << "Could not parse NL message " << e.what();
- }
-
- nlh = NLMSG_NEXT(nlh, numbytes);
- }
-
- close(nl_sock);
- return;
-}
-
-QueryData genPortInode(QueryContext &context) {
- QueryData results;
- getPortInode(results, AF_INET);
- getPortInode(results, AF_INET6);
- return results;
-}
-}
-}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+
+#include <boost/regex.hpp>
+
+#include <osquery/core.h>
+#include <osquery/filesystem.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+
+// From uapi/linux/sock_diag.h
+// From linux/sock_diag.h (<= 3.6)
+#ifndef SOCK_DIAG_BY_FAMILY
+#define SOCK_DIAG_BY_FAMILY 20
+#endif
+
+#include "inet_diag.h"
+
+namespace osquery {
+namespace tables {
+
+// heavily influenced by github.com/kristrev/inet-diag-example
+enum {
+ TCP_ESTABLISHED = 1,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_TIME_WAIT,
+ TCP_CLOSE,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_LISTEN,
+ TCP_CLOSING
+};
+
+#define TCPF_ALL 0xFFF
+#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
+
+int send_diag_msg(int sockfd, int protocol, int family) {
+ struct sockaddr_nl sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+
+ // Only interested in network sockets currently.
+ struct inet_diag_req_v2 conn_req;
+ memset(&conn_req, 0, sizeof(conn_req));
+ conn_req.sdiag_family = family;
+ conn_req.sdiag_protocol = protocol;
+ if (protocol == IPPROTO_TCP) {
+ conn_req.idiag_states =
+ TCPF_ALL &
+ ~((1 << TCP_SYN_RECV) | (1 << TCP_TIME_WAIT) | (1 << TCP_CLOSE));
+ // Request additional TCP information.
+ conn_req.idiag_ext |= (1 << (INET_DIAG_INFO - 1));
+ } else {
+ conn_req.idiag_states = -1;
+ }
+
+ struct nlmsghdr nlh;
+ memset(&nlh, 0, sizeof(nlh));
+ nlh.nlmsg_len = NLMSG_LENGTH(sizeof(conn_req));
+ nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+
+ struct iovec iov[4];
+ iov[0].iov_base = (void *)&nlh;
+ iov[0].iov_len = sizeof(nlh);
+ iov[1].iov_base = (void *)&conn_req;
+ iov[1].iov_len = sizeof(conn_req);
+
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (void *)&sa;
+ msg.msg_namelen = sizeof(sa);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ int retval = sendmsg(sockfd, &msg, 0);
+ return retval;
+}
+
+Row getDiagMessage(struct inet_diag_msg *diag_msg, int protocol, int family) {
+ char local_addr_buf[INET6_ADDRSTRLEN];
+ char remote_addr_buf[INET6_ADDRSTRLEN];
+
+ memset(local_addr_buf, 0, sizeof(local_addr_buf));
+ memset(remote_addr_buf, 0, sizeof(remote_addr_buf));
+
+ // set up data structures depending on idiag_family type
+ if (diag_msg->idiag_family == AF_INET) {
+ inet_ntop(AF_INET,
+ (struct in_addr *)&(diag_msg->id.idiag_src),
+ local_addr_buf,
+ INET_ADDRSTRLEN);
+ inet_ntop(AF_INET,
+ (struct in_addr *)&(diag_msg->id.idiag_dst),
+ remote_addr_buf,
+ INET_ADDRSTRLEN);
+ } else if (diag_msg->idiag_family == AF_INET6) {
+ inet_ntop(AF_INET6,
+ (struct in_addr6 *)&(diag_msg->id.idiag_src),
+ local_addr_buf,
+ INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6,
+ (struct in_addr6 *)&(diag_msg->id.idiag_dst),
+ remote_addr_buf,
+ INET6_ADDRSTRLEN);
+ }
+
+ // populate the Row from diag_msg fields
+ Row row;
+ row["socket"] = INTEGER(diag_msg->idiag_inode);
+ row["family"] = INTEGER(family);
+ row["protocol"] = INTEGER(protocol);
+ row["local_address"] = TEXT(local_addr_buf);
+ row["remote_address"] = TEXT(remote_addr_buf);
+ row["local_port"] = INTEGER(ntohs(diag_msg->id.idiag_sport));
+ row["remote_port"] = INTEGER(ntohs(diag_msg->id.idiag_dport));
+ return row;
+}
+
+void genSocketsForFamily(const std::map<std::string, std::string> socket_inodes,
+ int protocol,
+ int family,
+ QueryData &results) {
+ // set up the socket
+ int nl_sock = 0;
+ if ((nl_sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) {
+ return;
+ }
+
+ // send the inet_diag message
+ if (send_diag_msg(nl_sock, protocol, family) < 0) {
+ close(nl_sock);
+ return;
+ }
+
+ // recieve netlink messages
+ uint8_t recv_buf[SOCKET_BUFFER_SIZE];
+ int numbytes = recv(nl_sock, recv_buf, sizeof(recv_buf), 0);
+ if (numbytes <= 0) {
+ VLOG(1) << "NETLINK receive failed";
+ return;
+ }
+
+ auto nlh = (struct nlmsghdr *)recv_buf;
+ while (NLMSG_OK(nlh, numbytes)) {
+ if (nlh->nlmsg_type == NLMSG_DONE) {
+ break;
+ }
+
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
+ auto error = (struct nlmsgerr *) NLMSG_DATA(nlh);
+ VLOG(1) << "NETLINK message error " << error->error;
+ break;
+ }
+
+ // parse and process netlink message
+ auto diag_msg = (struct inet_diag_msg *)NLMSG_DATA(nlh);
+ auto row = getDiagMessage(diag_msg, protocol, family);
+
+ if (socket_inodes.count(row["socket"]) > 0) {
+ row["pid"] = socket_inodes.at(row["socket"]);
+ } else {
+ row["pid"] = "-1";
+ }
+
+ results.push_back(row);
+ nlh = NLMSG_NEXT(nlh, numbytes);
+ }
+
+ close(nl_sock);
+ return;
+}
+
+QueryData genOpenSockets(QueryContext &context) {
+ QueryData results;
+
+ // If a pid is given then set that as the only item in processes.
+ std::vector<std::string> processes;
+ if (!osquery::procProcesses(processes).ok()) {
+ VLOG(1) << "Cannot list Linux processes";
+ }
+
+ // Generate a map of socket inode to process tid.
+ boost::regex inode_regex("[0-9]+");
+ std::map<std::string, std::string> socket_inodes;
+ for (const auto& process : processes) {
+ std::map<std::string, std::string> descriptors;
+ if (osquery::procDescriptors(process, descriptors).ok()) {
+ for (const auto& fd : descriptors) {
+ if (fd.second.find("socket:") != std::string::npos) {
+ boost::smatch inode;
+ boost::regex_search(fd.second, inode, inode_regex);
+ if (inode[0].str().length() > 0) {
+ socket_inodes[inode[0].str()] = process;
+ }
+ }
+ }
+ }
+ }
+
+ // Use netlink messages to query socket information.
+ genSocketsForFamily(socket_inodes, IPPROTO_TCP, AF_INET, results);
+ genSocketsForFamily(socket_inodes, IPPROTO_UDP, AF_INET, results);
+ genSocketsForFamily(socket_inodes, IPPROTO_TCP, AF_INET6, results);
+ genSocketsForFamily(socket_inodes, IPPROTO_UDP, AF_INET6, results);
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <string>
-#include <iomanip>
-
-#include <stdlib.h>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <sys/socket.h>
#include <linux/netlink.h>
#include <boost/algorithm/string/trim.hpp>
-#include <glog/logging.h>
-
#include <osquery/core.h>
+#include <osquery/logger.h>
#include <osquery/tables.h>
+
#include "osquery/tables/networking/utils.h"
namespace osquery {
namespace tables {
#define MAX_NETLINK_SIZE 8192
+#define MAX_NETLINK_LATENCY 2000
-std::string netlink_ip(int family, const char* buffer) {
+std::string getNetlinkIP(int family, const char* buffer) {
char dst[INET6_ADDRSTRLEN];
memset(dst, 0, INET6_ADDRSTRLEN);
return address;
}
-int read_netlink(int socket_fd, char* output, int seq) {
+Status readNetlink(int socket_fd, int seq, char* output, size_t* size) {
struct nlmsghdr* nl_hdr;
- int bytes, message_size;
+ size_t message_size = 0;
do {
- bytes = recv(socket_fd, output, MAX_NETLINK_SIZE - message_size, 0);
- if (bytes < 0) {
- return -1;
+ int latency = 0;
+ int bytes = 0;
+ while (bytes == 0) {
+ bytes = recv(socket_fd, output, MAX_NETLINK_SIZE - message_size, 0);
+ if (bytes < 0) {
+ return Status(1, "Could not read from NETLINK");
+ } else if (latency >= MAX_NETLINK_LATENCY) {
+ return Status(1, "Netlink timeout");
+ } else if (bytes == 0) {
+ ::usleep(20);
+ latency += 20;
+ }
}
// Assure valid header response, and not an error type.
nl_hdr = (struct nlmsghdr*)output;
if (NLMSG_OK(nl_hdr, bytes) == 0 || nl_hdr->nlmsg_type == NLMSG_ERROR) {
- return -1;
+ return Status(1, "Read invalid NETLINK message");
}
if (nl_hdr->nlmsg_type == NLMSG_DONE) {
}
} while (nl_hdr->nlmsg_seq != seq || nl_hdr->nlmsg_pid != getpid());
- return message_size;
+ *size = message_size;
+ return Status(0, "OK");
}
void genNetlinkRoutes(const struct nlmsghdr* netlink_msg, QueryData& results) {
- struct rtmsg* message;
- struct rtattr* attr;
-
std::string address;
int mask = 0;
char interface[IF_NAMESIZE];
- bool has_destination;
- int attr_size;
-
- message = (struct rtmsg*)NLMSG_DATA(netlink_msg);
- attr = (struct rtattr*)RTM_RTA(message);
- attr_size = RTM_PAYLOAD(netlink_msg);
+ struct rtmsg* message = (struct rtmsg*)NLMSG_DATA(netlink_msg);
+ struct rtattr* attr = (struct rtattr*)RTM_RTA(message);
+ int attr_size = RTM_PAYLOAD(netlink_msg);
Row r;
// Iterate over each route in the netlink message
- has_destination = false;
+ bool has_destination = false;
r["metric"] = "0";
while (RTA_OK(attr, attr_size)) {
switch (attr->rta_type) {
r["interface"] = std::string(interface);
break;
case RTA_GATEWAY:
- address = netlink_ip(message->rtm_family, (char*)RTA_DATA(attr));
+ address = getNetlinkIP(message->rtm_family, (char*)RTA_DATA(attr));
r["gateway"] = address;
break;
case RTA_PREFSRC:
- address = netlink_ip(message->rtm_family, (char*)RTA_DATA(attr));
+ address = getNetlinkIP(message->rtm_family, (char*)RTA_DATA(attr));
r["source"] = address;
break;
case RTA_DST:
if (message->rtm_dst_len != 32 && message->rtm_dst_len != 128) {
mask = (int)message->rtm_dst_len;
}
- address = netlink_ip(message->rtm_family, (char*)RTA_DATA(attr));
+ address = getNetlinkIP(message->rtm_family, (char*)RTA_DATA(attr));
r["destination"] = address;
has_destination = true;
break;
QueryData genRoutes(QueryContext& context) {
QueryData results;
- void* netlink_buffer;
- struct nlmsghdr* netlink_msg;
-
- int socket_fd, size;
-
- socket_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ int socket_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (socket_fd < 0) {
- LOG(ERROR) << "Cannot open NETLINK socket.";
- return results;
+ VLOG(1) << "Cannot open NETLINK socket";
+ return {};
}
// Create netlink message header
- netlink_msg = (struct nlmsghdr*)malloc(MAX_NETLINK_SIZE);
- netlink_buffer = (void*)netlink_msg;
+ void* netlink_buffer = malloc(MAX_NETLINK_SIZE);
+ struct nlmsghdr* netlink_msg = (struct nlmsghdr*)netlink_buffer;
+ if (netlink_msg == nullptr) {
+ close(socket_fd);
+ return {};
+ }
+
netlink_msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
netlink_msg->nlmsg_type = RTM_GETROUTE; // routes from kernel routing table
netlink_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
// Send the netlink request to the kernel
if (send(socket_fd, netlink_msg, netlink_msg->nlmsg_len, 0) < 0) {
- LOG(ERROR) << "Cannot write NETLINK request header to socket.";
- goto cleanup;
+ VLOG(1) << "Cannot write NETLINK request header to socket";
+ close(socket_fd);
+ free(netlink_buffer);
+ return {};
}
// Wrap the read socket to support multi-netlink messages
- size = read_netlink(socket_fd, (char*)netlink_msg, 1);
- if (size < 0) {
- LOG(ERROR) << "Cannot read NETLINK response from socket.";
- goto cleanup;
+ size_t size;
+ if (!readNetlink(socket_fd, 1, (char*)netlink_msg, &size).ok()) {
+ VLOG(1) << "Cannot read NETLINK response from socket";
+ close(socket_fd);
+ free(netlink_buffer);
+ return {};
}
// Treat the netlink response as route information
netlink_msg = NLMSG_NEXT(netlink_msg, size);
}
-cleanup:
close(socket_fd);
- if (netlink_buffer != NULL) {
- free(netlink_buffer);
- }
-
+ free(netlink_buffer);
return results;
}
}
+++ /dev/null
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <boost/regex.hpp>
-#include <boost/algorithm/string.hpp>
-
-#include <glog/logging.h>
-
-#include <osquery/core.h>
-#include <osquery/tables.h>
-#include <osquery/filesystem.h>
-
-namespace osquery {
-namespace tables {
-
-void crawl_proc(QueryData& results) {
- std::vector<std::string> processes;
-
- if (!osquery::procProcesses(processes).ok()) {
- LOG(INFO) << "Cannot list Linux processes";
- return;
- }
-
- boost::regex socket_filter("[0-9]+");
- for (const auto& process : processes) {
- std::vector<std::string> descriptors;
- if (!osquery::procDescriptors(process, descriptors).ok()) {
- continue;
- }
-
- for (const auto& descriptor : descriptors) {
- std::string linkname;
- if (!procReadDescriptor(process, descriptor, linkname).ok()) {
- // This is an odd error case, but the symlink could not be read.
- continue;
- }
-
- if (linkname.find("socket") == std::string::npos) {
- // This is not a socket descriptor.
- continue;
- }
-
- // The linkname is in the form socket:[12345].
- boost::smatch inode;
- boost::regex_search(linkname, inode, socket_filter);
- if (inode[0].str().length() > 0) {
- Row r;
- r["pid"] = process;
- r["inode"] = inode[0].str();
- results.push_back(r);
- }
- }
- }
-
- return;
-}
-
-QueryData genSocketInode(QueryContext& context) {
- QueryData results;
- crawl_proc(results);
- return results;
-}
-}
-}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/sql.h>
+#include <osquery/tables.h>
+
+namespace osquery {
+namespace tables {
+
+typedef std::pair<std::string, std::string> ProtoFamilyPair;
+typedef std::map<std::string, std::vector<ProtoFamilyPair> > PortMap;
+
+QueryData genListeningPorts(QueryContext& context) {
+ QueryData results;
+
+ auto sockets = SQL::selectAllFrom("process_open_sockets");
+
+ PortMap ports;
+ for (const auto& socket : sockets) {
+ if (socket.at("remote_port") != "0") {
+ // Listening UDP/TCP ports have a remote_port == "0"
+ continue;
+ }
+
+ if (ports.count(socket.at("local_port")) > 0) {
+ bool duplicate = false;
+ for (const auto& entry : ports[socket.at("local_port")]) {
+ if (entry.first == socket.at("protocol") &&
+ entry.second == socket.at("family")) {
+ duplicate = true;
+ break;
+ }
+ }
+
+ if (duplicate) {
+ // There is a duplicate socket descriptor for this bind.
+ continue;
+ }
+ }
+
+ // Add this family/protocol/port bind to the tracked map.
+ ports[socket.at("local_port")].push_back(
+ std::make_pair(socket.at("protocol"), socket.at("family")));
+
+ Row r;
+ r["pid"] = socket.at("pid");
+ r["port"] = socket.at("local_port");
+ r["protocol"] = socket.at("protocol");
+ r["family"] = socket.at("family");
+ r["address"] = socket.at("local_address");
+
+ results.push_back(r);
+ }
+
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <iomanip>
#include <sstream>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#pragma once
# Example: add tables that are not yet ready for release
quarantine
-suid_bin
+++ /dev/null
-table_name("port_inode")
-schema([
- Column("local_port", TEXT),
- Column("remote_port", TEXT),
- Column("local_ip", TEXT),
- Column("remote_ip", TEXT),
- Column("inode", TEXT),
- Column("family", INTEGER),
-])
-implementation("osquery/tables/networking/linux/port_inode@genPortInode")
-
+++ /dev/null
-table_name("socket_inode")
-schema([
- Column("pid", TEXT),
- Column("inode", TEXT),
-])
-implementation("osquery/tables/networking/linux/socket_inode@genSocketInode")
--- /dev/null
+table_name("acpi_tables")
+schema([
+ Column("name", TEXT),
+ Column("size", INTEGER),
+ Column("md5", TEXT),
+])
+implementation("system/acpi_tables@genACPITables")
--- /dev/null
+table_name("etc_services")
+description("Line-parsed /etc/services.")
+schema([
+ Column("name", TEXT),
+ Column("port", INTEGER),
+ Column("protocol", TEXT),
+ Column("aliases", TEXT, "Optional space separated list of other names for a service"),
+ Column("comment", TEXT, "Optional comment for a service."),
+])
+implementation("etc_services@genEtcServices")
+
Column("model_id", INTEGER),
Column("vendor", TEXT),
Column("vendor_id", INTEGER),
- Column("serial", INTEGER),
+ Column("serial", TEXT),
Column("revision", INTEGER),
Column("time", INTEGER),
])
Column("path", TEXT, "Must provide a path or directory", required=True),
Column("directory", TEXT, "Must provide a path or directory", required=True),
Column("md5", TEXT),
+ Column("sha1", TEXT),
+ Column("sha256", TEXT),
])
implementation("utility/hash@genHash")
--- /dev/null
+table_name("listening_ports")
+schema([
+ Column("pid", INTEGER),
+ Column("port", INTEGER),
+ Column("protocol", INTEGER),
+ Column("family", INTEGER),
+ Column("address", TEXT),
+])
+implementation("listening_ports@genListeningPorts")
--- /dev/null
+table_name("osquery_flags")
+schema([
+ Column("name", TEXT),
+ Column("type", TEXT),
+ Column("description", TEXT),
+ Column("default_value", TEXT),
+ Column("value", TEXT),
+ Column("shell_only", INTEGER),
+])
+implementation("osquery@genOsqueryFlags")
--- /dev/null
+table_name("osquery_info")
+schema([
+ Column("version", TEXT),
+ Column("config_md5", TEXT),
+ Column("config_path", TEXT),
+ Column("pid", INTEGER),
+])
+implementation("osquery@genOsqueryInfo")
--- /dev/null
+table_name("pci_devices")
+schema([
+ Column("pci_slot", TEXT),
+ Column("pci_class", TEXT),
+ Column("driver", TEXT),
+ Column("vendor", TEXT),
+ Column("vendor_id", TEXT),
+ Column("model", TEXT),
+ Column("model_id", TEXT),
+
+ # Optional columns
+ #Column("subsystem", TEXT),
+ #Column("express", INTEGER),
+ #Column("thunderbolt", INTEGER),
+ #Column("removable", INTEGER),
+])
+implementation("pci_devices@genPCIDevices")
table_name("process_open_files")
schema([
- Column("pid", INTEGER),
- Column("file_type", TEXT),
- Column("local_path", TEXT),
- Column("local_host", TEXT),
- Column("local_port", TEXT),
- Column("remote_host", TEXT),
- Column("remote_port", TEXT),
+ Column("pid", BIGINT),
+ Column("fd", BIGINT),
+ Column("path", TEXT),
])
-implementation("system/processes@genProcessOpenFiles")
+implementation("system/process_open_files@genOpenFiles")
--- /dev/null
+table_name("process_open_sockets")
+schema([
+ Column("pid", INTEGER),
+ Column("socket", INTEGER),
+ Column("family", INTEGER),
+ Column("protocol", INTEGER),
+ Column("local_address", TEXT),
+ Column("remote_address", TEXT),
+ Column("local_port", INTEGER),
+ Column("remote_port", INTEGER),
+])
+implementation("system/process_open_sockets@genOpenSockets")
+
--- /dev/null
+table_name("smbios_tables")
+schema([
+ Column("number", INTEGER),
+ Column("type", INTEGER),
+ Column("description", TEXT),
+ Column("handle", INTEGER),
+ Column("header_size", INTEGER),
+ Column("size", INTEGER),
+ Column("md5", TEXT),
+])
+implementation("system/smbios_tables@genSMBIOSTables")
--- /dev/null
+table_name("usb_devices")
+schema([
+ Column("usb_address", INTEGER),
+ Column("usb_port", INTEGER),
+ Column("vendor", TEXT),
+ Column("vendor_id", TEXT),
+ Column("model", TEXT),
+ Column("model_id", TEXT),
+ Column("serial", TEXT),
+ Column("removable", INTEGER),
+])
+implementation("usb_devices@genUSBDevices")
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <vector>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <vector>
#include <string>
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/core.h>
+#include <osquery/filesystem.h>
+#include <osquery/hash.h>
+#include <osquery/tables.h>
+
+namespace fs = boost::filesystem;
+
+namespace osquery {
+namespace tables {
+
+const std::string kLinuxACPIPath = "/sys/firmware/acpi/tables";
+
+void genACPITable(const std::string& table, QueryData& results) {
+ fs::path table_path = table;
+
+ // There may be "categories" of tables in the form of directories.
+ Status status;
+ if (!fs::is_regular_file(table_path)) {
+ std::vector<std::string> child_tables;
+ status = osquery::listFilesInDirectory(table_path, child_tables);
+ if (status.ok()) {
+ for (const auto& child_table : child_tables) {
+ genACPITable(table, results);
+ }
+ }
+
+ return;
+ }
+
+ Row r;
+ r["name"] = table_path.filename().string();
+
+ std::string table_content;
+ status = osquery::readFile(table_path, table_content);
+ if (!status.ok()) {
+ r["size"] = INTEGER(-1);
+ } else {
+ r["size"] = INTEGER(table_content.size());
+ r["md5"] = osquery::hashFromBuffer(
+ HASH_TYPE_MD5, table_content.c_str(), table_content.length());
+ }
+
+ results.push_back(r);
+}
+
+QueryData genACPITables(QueryContext& context) {
+ QueryData results;
+
+ // In Linux, hopefully the ACPI tables are parsed and exposed as nodes.
+ std::vector<std::string> tables;
+ auto status = osquery::listFilesInDirectory(kLinuxACPIPath, tables);
+ if (!status.ok()) {
+ // We could not read the tables path or the nodes are not exposed.
+ return {};
+ }
+
+ for (const auto& table : tables) {
+ genACPITable(table, results);
+ }
+
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <set>
#include <mutex>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <fstream>
QueryData results;
if (!pathExists(kKernelModulePath).ok()) {
- LOG(ERROR) << "Cannot find kernel modules proc file: " << kKernelModulePath;
- return results;
+ VLOG(1) << "Cannot find kernel modules proc file: " << kKernelModulePath;
+ return {};
}
// Cannot seek to the end of procfs.
std::ifstream fd(kKernelModulePath, std::ios::in);
if (!fd) {
- LOG(ERROR) << "Cannot read kernel modules from: " << kKernelModulePath;
- return results;
+ VLOG(1) << "Cannot read kernel modules from: " << kKernelModulePath;
+ return {};
}
auto module_info = std::string(std::istreambuf_iterator<char>(fd),
for (const auto& module : split(module_info, "\n")) {
Row r;
auto module_info = split(module, " ");
-
if (module_info.size() < 6) {
// Interesting error case, this module line is not well formed.
continue;
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <mntent.h>
#include <sys/vfs.h>
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+
+#include "osquery/events/linux/udev.h"
+
+namespace osquery {
+namespace tables {
+
+const std::string kPCIKeySlot = "PCI_SLOT_NAME";
+const std::string kPCIKeyClass = "ID_PCI_CLASS_FROM_DATABASE";
+const std::string kPCIKeyVendor = "ID_VENDOR_FROM_DATABASE";
+const std::string kPCIKeyModel = "ID_MODEL_FROM_DATABASE";
+const std::string kPCIKeyID = "PCI_ID";
+const std::string kPCIKeyDriver = "DRIVER";
+
+QueryData genPCIDevices(QueryContext &context) {
+ QueryData results;
+
+ auto udev_handle = udev_new();
+ if (udev_handle == nullptr) {
+ VLOG(1) << "Could not get udev handle.";
+ return results;
+ }
+
+ // Perform enumeration/search.
+ auto enumerate = udev_enumerate_new(udev_handle);
+ udev_enumerate_add_match_subsystem(enumerate, "pci");
+ udev_enumerate_scan_devices(enumerate);
+
+ // Get list entries and iterate over entries.
+ struct udev_list_entry *device_entries, *entry;
+ device_entries = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(entry, device_entries) {
+ const char *path = udev_list_entry_get_name(entry);
+ auto device = udev_device_new_from_syspath(udev_handle, path);
+
+ Row r;
+ r["pci_slot"] = UdevEventPublisher::getValue(device, kPCIKeySlot);
+ r["pci_class"] = UdevEventPublisher::getValue(device, kPCIKeyClass);
+ r["driver"] = UdevEventPublisher::getValue(device, kPCIKeyDriver);
+ r["vendor"] = UdevEventPublisher::getValue(device, kPCIKeyVendor);
+ r["model"] = UdevEventPublisher::getValue(device, kPCIKeyModel);
+
+ // VENDOR:MODEL ID is in the form of HHHH:HHHH.
+ std::vector<std::string> ids;
+ auto device_id = UdevEventPublisher::getValue(device, kPCIKeyID);
+ boost::split(ids, device_id, boost::is_any_of(":"));
+ if (ids.size() == 2) {
+ r["vendor_id"] = ids[0];
+ r["model_id"] = ids[1];
+ }
+
+ // Set invalid vendor/model IDs to 0.
+ if (r["vendor_id"].size() == 0) {
+ r["vendor_id"] = "0";
+ }
+
+ if (r["model_id"].size() == 0) {
+ r["model_id"] = "0";
+ }
+
+ results.push_back(r);
+ udev_device_unref(device);
+ }
+
+ // Drop references to udev structs.
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev_handle);
+
+ return results;
+}
+}
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+#include <osquery/filesystem.h>
+
+namespace osquery {
+namespace tables {
+
+void genDescriptors(const std::string& process,
+ const std::map<std::string, std::string>& descriptors,
+ QueryData& results) {
+ for (const auto& fd : descriptors) {
+ if (fd.second.find("socket:") != std::string::npos ||
+ fd.second.find("anon_inode:") != std::string::npos ||
+ fd.second.find("pipe:") != std::string::npos) {
+ // This is NOT a vnode/file descriptor.
+ continue;
+ }
+
+ Row r;
+ r["pid"] = process;
+ r["fd"] = fd.first;
+ r["path"] = fd.second;
+ results.push_back(r);
+ }
+
+ return;
+}
+
+QueryData genOpenFiles(QueryContext& context) {
+ QueryData results;
+
+ std::vector<std::string> processes;
+ if (!osquery::procProcesses(processes).ok()) {
+ VLOG(1) << "Cannot list Linux processes";
+ return results;
+ }
+
+ for (const auto& process : processes) {
+ std::map<std::string, std::string> descriptors;
+ if (osquery::procDescriptors(process, descriptors).ok()) {
+ genDescriptors(process, descriptors, results);
+ }
+ }
+
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <string>
#include <fstream>
#include <unistd.h>
#include <proc/readproc.h>
+#include <boost/algorithm/string/trim.hpp>
+
#include <osquery/core.h>
#include <osquery/tables.h>
#include <osquery/filesystem.h>
#endif
std::string proc_name(const proc_t* proc_info) {
- char cmd[17]; // cmd is a 16 char buffer
-
- memset(cmd, 0, 17);
- memcpy(cmd, proc_info->cmd, 16);
- return std::string(cmd);
+ return std::string(proc_info->cmd);
}
std::string proc_attr(const std::string& attr, const proc_t* proc_info) {
r["euid"] = BIGINT((unsigned int)proc_info->euid);
r["egid"] = BIGINT((unsigned int)proc_info->egid);
r["name"] = proc_name(proc_info);
- r["cmdline"] = proc_cmdline(proc_info);
+ std::string cmdline = proc_cmdline(proc_info);
+ boost::algorithm::trim(cmdline);
+ r["cmdline"] = cmdline;
r["path"] = proc_link(proc_info);
r["on_disk"] = osquery::pathExists(r["path"]).toString();
return results;
}
-
-QueryData genProcessOpenFiles(QueryContext& context) {
- QueryData results;
- return results;
-}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/core.h>
+#include <osquery/filesystem.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+
+#include "osquery/tables/system/smbios_utils.h"
+
+namespace osquery {
+namespace tables {
+
+#define kLinuxSMBIOSRawAddress_ 0xF0000
+#define kLinuxSMBIOSRawLength_ 0x10000
+
+const std::string kLinuxEFISystabPath = "/sys/firmware/efi/systab";
+const std::string kLinuxLegacyEFISystabPath = "/proc/efi/systab";
+
+void genSMBIOSFromDMI(size_t base, size_t length, QueryData& results) {
+ // Linux will expose the SMBIOS/DMI entry point structures, which contain
+ // a member variable with the DMI tables start address and size.
+ // This applies to both the EFI-variable and physical memory search.
+ uint8_t* data;
+ auto status = osquery::readRawMem(base, length, (void**)&data);
+ if (!status.ok()) {
+ VLOG(1) << "Could not read DMI tables memory";
+ return;
+ }
+
+ // Attempt to parse tables from allocated data.
+ genSMBIOSTables(data, length, results);
+ free(data);
+}
+
+void genEFISystabTables(QueryData& results) {
+ // Not yet supported.
+ return;
+}
+
+void genRawSMBIOSTables(QueryData& results) {
+ uint8_t* data;
+ auto status = osquery::readRawMem(
+ kLinuxSMBIOSRawAddress_, kLinuxSMBIOSRawLength_, (void**)&data);
+ if (!status.ok()) {
+ VLOG(1) << "Could not read SMBIOS memory";
+ return;
+ }
+
+ // Search for the SMBIOS/DMI tables magic header string.
+ size_t offset;
+ for (offset = 0; offset <= 0xFFF0; offset += 16) {
+ // Could look for "_SM_" for the SMBIOS header, but the DMI header exists
+ // in both SMBIOS and the legacy DMI spec.
+ if (memcmp(data + offset, "_DMI_", 5) == 0) {
+ auto dmi_data = (DMIEntryPoint*)(data + offset);
+ genSMBIOSFromDMI(dmi_data->tableAddress, dmi_data->tableLength, results);
+ }
+ }
+
+ free(data);
+}
+
+QueryData genSMBIOSTables(QueryContext& context) {
+ QueryData results;
+
+ if (osquery::isReadable(kLinuxEFISystabPath).ok() ||
+ osquery::isReadable(kLinuxLegacyEFISystabPath).ok()) {
+ genEFISystabTables(results);
+ } else {
+ genRawSMBIOSTables(results);
+ }
+
+ return results;
+}
+}
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/core.h>
+#include <osquery/logger.h>
+#include <osquery/tables.h>
+
+#include "osquery/events/linux/udev.h"
+
+namespace osquery {
+namespace tables {
+
+const std::string kUSBKeyVendorID = "ID_VENDOR_ID";
+const std::string kUSBKeyVendor = "ID_VENDOR_FROM_DATABASE";
+const std::string kUSBKeyModelID = "ID_MODEL_ID";
+const std::string kUSBKeyModel = "ID_MODEL_FROM_DATABASE";
+const std::string kUSBKeyDriver = "ID_USB_DRIVER";
+const std::string kUSBKeySubsystem = "SUBSYSTEM";
+const std::string kUSBKeySerial = "ID_SERIAL_SHORT";
+const std::string kUSBKeyAddress = "BUSNUM";
+const std::string kUSBKeyPort = "DEVNUM";
+
+QueryData genUSBDevices(QueryContext &context) {
+ QueryData results;
+
+ auto udev_handle = udev_new();
+ if (udev_handle == nullptr) {
+ VLOG(1) << "Could not get udev handle.";
+ return results;
+ }
+
+ // Perform enumeration/search.
+ auto enumerate = udev_enumerate_new(udev_handle);
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_scan_devices(enumerate);
+
+ // Get list entries and iterate over entries.
+ struct udev_list_entry *device_entries, *entry;
+ device_entries = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(entry, device_entries) {
+ const char *path = udev_list_entry_get_name(entry);
+ auto device = udev_device_new_from_syspath(udev_handle, path);
+
+ Row r;
+ // r["driver"] = UdevEventPublisher::getValue(device, kUSBKeyDriver);
+ r["vendor"] = UdevEventPublisher::getValue(device, kUSBKeyVendor);
+ r["model"] = UdevEventPublisher::getValue(device, kUSBKeyModel);
+
+ // USB-specific vendor/model ID properties.
+ r["model_id"] = UdevEventPublisher::getValue(device, kUSBKeyModelID);
+ r["vendor_id"] = UdevEventPublisher::getValue(device, kUSBKeyVendorID);
+ r["serial"] = UdevEventPublisher::getValue(device, kUSBKeySerial);
+
+ // Address/port accessors.
+ r["usb_address"] = UdevEventPublisher::getValue(device, kUSBKeyAddress);
+ r["usb_port"] = UdevEventPublisher::getValue(device, kUSBKeyPort);
+
+ // Removable detection.
+ auto removable = UdevEventPublisher::getAttr(device, "removable");
+ if (removable == "unknown") {
+ r["removable"] = "-1";
+ } else {
+ r["removable"] = "1";
+ }
+
+ if (r["usb_address"].size() > 0 && r["usb_port"].size() > 0) {
+ results.push_back(r);
+ }
+ udev_device_unref(device);
+ }
+
+ // Drop references to udev structs.
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev_handle);
+
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <set>
#include <mutex>
-// Copyright 2004-present Wesley Shields <wxs@atarininja.org>.
-// All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <mutex>
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <string>
#include <vector>
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/hash.h>
+
+#include "osquery/tables/system/smbios_utils.h"
+
+namespace osquery {
+namespace tables {
+
+const std::map<int, std::string> kSMBIOSTypeDescriptions = {
+ {0, "BIOS Information"},
+ {1, "System Information"},
+ {2, "Base Board or Module Information"},
+ {3, "System Enclosure or Chassis"},
+ {4, "Processor Information"},
+ {5, "Memory Controller Information"},
+ {6, "Memory Module Information"},
+ {7, "Cache Information"},
+ {8, "Port Connector Information"},
+ {9, "System Slots"},
+ {10, "On Board Devices Information"},
+ {11, "OEM Strings"},
+ {12, "System Configuration Options"},
+ {13, "BIOS Language Information"},
+ {14, "Group Associations"},
+ {15, "System Event Log"},
+ {16, "Physical Memory Array"},
+ {17, "Memory Device"},
+ {18, "32-bit Memory Error Information"},
+ {19, "Memory Array Mapped Address"},
+ {20, "Memory Device Mapped Address"},
+ {21, "Built-in Pointing Device"},
+ {22, "Portable Battery"},
+ {23, "System Reset"},
+ {24, "Hardware Security"},
+ {25, "System Power Controls"},
+ {26, "Voltage Probe"},
+ {27, "Cooling Device"},
+ {28, "Temperature Probe"},
+ {29, "Electrical Current Probe"},
+ {30, "Out-of-Band Remote Access"},
+ {31, "Boot Integrity Services"},
+ {32, "System Boot Information"},
+ {33, "64-bit Memory Error Information"},
+ {34, "Management Device"},
+ {35, "Management Device Component"},
+ {36, "Management Device Threshold Data"},
+ {37, "Memory Channel"},
+ {38, "IPMI Device Information"},
+ {39, "System Power Supply"},
+ {40, "Additional Information"},
+ {41, "Onboard Devices Extended Info"},
+ {126, "Inactive"},
+ {127, "End-of-Table"},
+ {130, "Memory SPD Data"},
+ {131, "OEM Processor Type"},
+ {132, "OEM Processor Bus Speed"},
+};
+
+void genSMBIOSTables(const uint8_t* tables, size_t length, QueryData& results) {
+ // Keep a pointer to the end of the SMBIOS data for comparison.
+ auto tables_end = tables + length;
+ auto table = tables;
+
+ // Iterate through table structures within SMBIOS data range.
+ size_t index = 0;
+ while (table + sizeof(SMBStructHeader) <= tables_end) {
+ auto header = (const SMBStructHeader*)table;
+ if (table + header->length > tables_end) {
+ // Invalid header, length must be within SMBIOS data range.
+ break;
+ }
+
+ Row r;
+ // The index is a supliment that keeps track of table order.
+ r["number"] = INTEGER(index++);
+ r["type"] = INTEGER((unsigned short)header->type);
+ if (kSMBIOSTypeDescriptions.count(header->type) > 0) {
+ r["description"] = kSMBIOSTypeDescriptions.at(header->type);
+ }
+
+ r["handle"] = BIGINT((unsigned long long)header->handle);
+ r["header_size"] = INTEGER((unsigned short)header->length);
+
+ // The SMBIOS structure may have unformatted, double-NULL delimited trailing
+ // data, which are usually strings.
+ auto next_table = table + header->length;
+ for (; next_table + sizeof(SMBStructHeader) <= tables_end; next_table++) {
+ if (next_table[0] == 0 && next_table[1] == 0) {
+ next_table += 2;
+ break;
+ }
+ }
+
+ auto table_length = next_table - table;
+ r["size"] = INTEGER(table_length);
+ r["md5"] = hashFromBuffer(HASH_TYPE_MD5, table, table_length);
+
+ table = next_table;
+ results.push_back(r);
+ }
+}
+}
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/tables.h>
+
+namespace osquery {
+namespace tables {
+
+typedef struct SMBStructHeader {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+} __attribute__((packed)) SMBStructHeader;
+
+typedef struct DMIEntryPoint {
+ uint8_t anchor[5];
+ uint8_t checksum;
+ uint16_t tableLength;
+ uint32_t tableAddress;
+ uint16_t structureCount;
+ uint8_t bcdRevision;
+} __attribute__((packed)) DMIEntryPoint;
+
+extern const std::map<int, std::string> kSMBIOSTypeDescriptions;
+
+void genSMBIOSTables(const uint8_t* tables, size_t length, QueryData& results);
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <ctime>
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
#include <boost/filesystem.hpp>
-#include <boost/system/system_error.hpp>
+#include <osquery/filesystem.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
+namespace fs = boost::filesystem;
+
namespace osquery {
namespace tables {
-Status genBin(const boost::filesystem::path& path,
- int perms,
- QueryData& results) {
+std::vector<std::string> kBinarySearchPaths = {
+ "/bin",
+ "/sbin",
+ "/usr/bin",
+ "/usr/sbin",
+ "/usr/local/bin",
+ "/usr/local/sbin",
+ "/tmp",
+};
+
+Status genBin(const fs::path& path, int perms, QueryData& results) {
struct stat info;
// store user and group
if (stat(path.c_str(), &info) != 0) {
// store path
Row r;
r["path"] = path.string();
-
struct passwd *pw = getpwuid(info.st_uid);
struct group *gr = getgrgid(info.st_gid);
return Status(0, "OK");
}
-QueryData genSuidBin(QueryContext& context) {
- QueryData results;
- boost::system::error_code error;
-
-#if defined(UBUNTU)
- // When building on supported Ubuntu systems, boost may ABRT.
- if (geteuid() != 0) {
- return results;
+bool isSuidBin(const fs::path& path, int perms) {
+ if (!fs::is_regular_file(path)) {
+ return false;
}
-#endif
- boost::filesystem::recursive_directory_iterator it =
- boost::filesystem::recursive_directory_iterator(
- boost::filesystem::path("/"), error);
+ if ((perms & 04000) == 04000 || (perms & 02000) == 02000) {
+ return true;
+ }
+ return false;
+}
- if (error.value() != boost::system::errc::success) {
- LOG(ERROR) << "Error opening \"/\": " << error.message();
- return results;
+void genSuidBinsFromPath(const std::string& path, QueryData& results) {
+ if (!pathExists(path).ok()) {
+ // Creating an iterator on a missing path will except.
+ return;
}
- boost::filesystem::recursive_directory_iterator end;
+ auto it = fs::recursive_directory_iterator(fs::path(path));
+ fs::recursive_directory_iterator end;
while (it != end) {
- boost::filesystem::path path = *it;
+ fs::path path = *it;
try {
+ // Do not traverse symlinked directories.
+ if (fs::is_directory(path) && fs::is_symlink(path)) {
+ it.no_push();
+ }
+
int perms = it.status().permissions();
- if (boost::filesystem::is_regular_file(path) &&
- ((perms & 04000) == 04000 || (perms & 02000) == 02000)) {
+ if (isSuidBin(path, perms)) {
+ // Only emit suid bins.
genBin(path, perms, results);
}
- } catch (...) {
- // handle invalid files like /dev/fd/3
- }
- try {
+
++it;
- } catch (std::exception &ex) {
- it.no_push(); // handle permission error.
+ } catch (fs::filesystem_error& e) {
+ VLOG(1) << "Cannot read binary from " << path;
+ it.no_push();
+ // Try to recover, otherwise break.
+ try { ++it; } catch(fs::filesystem_error& e) { break; }
}
}
+}
+
+QueryData genSuidBin(QueryContext& context) {
+ QueryData results;
+
+ // Todo: add hidden column to select on that triggers non-std path searches.
+ for (const auto& path : kBinarySearchPaths) {
+ genSuidBinsFromPath(path, results);
+ }
return results;
}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
/*
** This file is generated. Do not modify it manually!
*/
+#include <osquery/events.h>
#include <osquery/tables.h>
+
#include "osquery/core/virtual_table.h"
namespace osquery { namespace tables {
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
/*
** This file is generated. Do not modify it manually!
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
/*
** This file is generated. Do not modify it manually!
*/
+#include <osquery/events.h>
#include <osquery/tables.h>
+
#include "osquery/core/virtual_table.h"
namespace osquery { namespace tables {
{% else %}
class {{class_name}} {
public:
- static osquery::QueryData {{function}}(QueryContext& request);
+ osquery::QueryData {{function}}(QueryContext& request);
};
{% endif %}\
QueryData generate(QueryContext& request) {
{% if class_name != "" %}\
- return osquery::tables::{{class_name}}::{{function}}(request);
+ auto subscriber = EventFactory::getEventSubscriber("{{class_name}}");
+ return subscriber->{{function}}(request);
{% else %}\
return osquery::tables::{{function}}(request);
{% endif %}\
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <boost/filesystem.hpp>
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "osquery/core/md5.h"
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <boost/filesystem.hpp>
-#include <osquery/tables.h>
#include <osquery/filesystem.h>
+#include <osquery/hash.h>
+#include <osquery/tables.h>
namespace osquery {
namespace tables {
QueryData genHash(QueryContext& context) {
QueryData results;
- osquery::md5::MD5 digest;
auto paths = context.constraints["path"].getAll(EQUALS);
for (const auto& path_string : paths) {
if (!boost::filesystem::is_regular_file(path)) {
continue;
}
+
Row r;
r["path"] = path.string();
- r["md5"] = std::string(digest.digestFile(path.c_str()));
r["directory"] = path.parent_path().string();
+ r["md5"] = osquery::hashFromFile(HASH_TYPE_MD5, path.string());
+ r["sha1"] = osquery::hashFromFile(HASH_TYPE_SHA1, path.string());
+ r["sha256"] = osquery::hashFromFile(HASH_TYPE_SHA256, path.string());
results.push_back(r);
}
r["path"] = begin->path().string();
r["directory"] = directory_string;
if (boost::filesystem::is_regular_file(begin->status())) {
- r["md5"] = digest.digestFile(begin->path().string().c_str());
+ r["md5"] = osquery::hashFromFile(HASH_TYPE_MD5, begin->path().string());
+ r["sha1"] =
+ osquery::hashFromFile(HASH_TYPE_SHA1, begin->path().string());
+ r["sha256"] =
+ osquery::hashFromFile(HASH_TYPE_SHA256, begin->path().string());
}
results.push_back(r);
}
--- /dev/null
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#include <osquery/config.h>
+#include <osquery/core.h>
+#include <osquery/flags.h>
+#include <osquery/logger.h>
+#include <osquery/sql.h>
+#include <osquery/tables.h>
+
+namespace osquery {
+namespace tables {
+
+void genFlag(const std::string& name,
+ const FlagDetail& flag,
+ bool is_shell,
+ QueryData& results) {
+ Row r;
+ r["name"] = name;
+ r["type"] = std::get<0>(flag);
+ r["description"] = std::get<2>(flag);
+ r["default_value"] = std::get<1>(flag);
+ r["value"] = Flag::get().getValue(name);
+ r["shell_only"] = (is_shell) ? "1" : "0";
+ results.push_back(r);
+}
+
+QueryData genOsqueryFlags(QueryContext& context) {
+ QueryData results;
+
+ auto flags = Flag::get().flags();
+ for (const auto& flag : flags) {
+ genFlag(flag.first, flag.second, false, results);
+ }
+
+ auto shell_flags = Flag::get().shellFlags();
+ for (const auto& flag : shell_flags) {
+ genFlag(flag.first, flag.second, true, results);
+ }
+
+ return results;
+}
+
+QueryData genOsqueryInfo(QueryContext& context) {
+ QueryData results;
+
+ Row r;
+ r["version"] = TEXT(OSQUERY_VERSION);
+ r["pid"] = INTEGER(getpid());
+
+ std::string hash_string;
+ auto s = Config::getInstance()->getMD5(hash_string);
+ if (s.ok()) {
+ r["config_md5"] = TEXT(hash_string);
+ } else {
+ VLOG(1) << "Could not retrieve config hash: " << s.toString();
+ }
+
+ r["config_path"] = Flag::get().getValue("config_path");
+ results.push_back(r);
+
+ return results;
+}
+}
+}
-// Copyright 2004-present Facebook. All Rights Reserved.
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
#include <ctime>
Name: osquery
-Version: 1.2.0
+Version: 1.3.1
Release: 0
License: Apache-2.0 and GPLv2
Summary: A SQL powered operating system instrumentation, monitoring framework.
BuildRequires: readline-devel
BuildRequires: pkgconfig(libprocps)
BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(openssl)
BuildRequires: python-jinja2
Requires: glog
Requires: gflag
%files test
%manifest %{name}.manifest
+%{_bindir}/osquery_hash_tests
%{_bindir}/osquery_status_tests
%{_bindir}/osquery_db_handle_tests
%{_bindir}/osquery_results_tests
%{_bindir}/osquery_sql_tests
%{_bindir}/osquery_sqlite_util_tests
%{_bindir}/osquery_scheduler_tests
+%{_bindir}/osquery_tables_tests
%{_bindir}/osquery_test_util_tests
%{_bindir}/osquery_text_tests
%{_bindir}/osquery_logger_tests
#!/usr/bin/env python
-# Copyright 2004-present Facebook. All Rights Reserved.
+
+# Copyright (c) 2014, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
from __future__ import absolute_import
from __future__ import division
#!/usr/bin/env python
-# Copyright 2004-present Facebook. All Rights Reserved.
+
+# Copyright (c) 2014, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
from __future__ import absolute_import
from __future__ import division
TEMPLATES = {}
# Temporary reserved column names
-RESERVED = ["n"]
+RESERVED = ["n", "index"]
# Supported SQL types for spec
for j in range(i):
dir_path += "%s/" % path_bits[j]
if not os.path.exists(dir_path):
- os.mkdir(dir_path)
+ try:
+ os.mkdir(dir_path)
+ except:
+ # May encounter a race when using a make jobserver.
+ pass
logging.debug("generating %s" % path)
with open(path, "w+") as file_h:
file_h.write(self.impl_content)
--- /dev/null
+{
+ /* Configure the daemon below */
+ "options": {
+ // Select the osquery config plugin.
+ "config_retriever": "filesystem",
+
+ // Select the osquery logging plugin.
+ "log_receiver": "filesystem",
+
+ // The log directory stores info, warning, and errors.
+ // If the daemon uses the 'filesystem' logging retriever then the log_dir
+ // will also contain the query results.
+ //"osquery_log_dir": "/var/log/osquery",
+
+ // Set 'disable_logging' to true to prevent writing any info, warning, error
+ // logs. If a logging plugin is selected it will still write query results.
+ //"disable_logging": "false",
+
+ // Query differential results are logged as change-events to assist log
+ // aggregation operatinos like searching and transactons.
+ // Set 'log_results_events' to log differentials as transactions.
+ //"log_result_events": "true",
+
+ // Splay the scheduled interval for queries.
+ // This is very helpful to prevent system performance impact when scheduling
+ // large numbers of queries that run a smaller or similar intervals.
+ //"schedule_splay_percent": "10",
+
+ // Use the system hostname as an identifier for results.
+ // If hostnames change with DHCP a more static option is 'uuid'.
+ //"host_identifier": "hostname",
+
+ // Write the pid of the osqueryd process to a pidfile/mutex.
+ //"pidfile": "/var/osquery/osquery.pidfile",
+
+ // Disable the osquery event pubsub functionallity.
+ // Many tables depend on internal OS API events.
+ //"event_pubsub": "true",
+
+ // Clear events from the osquery backing store after a number of seconds.
+ "event_pubsub_expiry": "86000",
+
+ // A filesystem path for disk-based backing storage used for events and
+ // and query results differentials. See also 'use_in_memory_database'.
+ //"db_path": "/var/osquery/osquery.db",
+
+ // If using a third-party backing store you may want to run completely in
+ // memory. Currently rocksdb must use disk-based storage.
+ //"use_in_memory_database": "false",
+
+ // Enable debug or verbose debug output when logging.
+ "debug": "false",
+ "verbose_debug": "false",
+
+ // The number of threads for concurrent query schedule execution.
+ "worker_threads": "4"
+ },
+
+ /* Define a schedule of queries */
+ "scheduledQueries": [
+ // This is a simple example query that outputs information about osquery.
+ {
+ // More complicated queries benefit from a name such as 'my_processes'.
+ "name": "info",
+ // The exact query to run, include a semi-colon.
+ "query": "SELECT * FROM osquery_info;",
+ // The interval in seconds to run this query, not an exact interval.
+ "interval": 3600
+ }
+ ]
+}
--- /dev/null
+{
+ "scheduledQueries": [
+ {
+ "name": "time",
+ "query": "select * from time;",
+ "interval": 1
+ }
+ ]
+}
--- /dev/null
+MIIESzCCAzOgAwIBAgIJAI1bGeY2YPlhMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD
+VQQGEwItLTESMBAGA1UECAwJU29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZ
+MBcGA1UECgwQU29tZU9yZ2FuaXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXph
+dGlvbmFsVW5pdDEeMBwGA1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJ
+KoZIhvcNAQkBFhpyb290QGxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xNDA4MTkx
+OTEyMTZaFw0xNTA4MTkxOTEyMTZaMIG7MQswCQYDVQQGEwItLTESMBAGA1UECAwJ
+U29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZMBcGA1UECgwQU29tZU9yZ2Fu
+aXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXphdGlvbmFsVW5pdDEeMBwGA1UE
+AwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJKoZIhvcNAQkBFhpyb290QGxv
+Y2FsaG9zdC5sb2NhbGRvbWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAM6EsaVoMaHrYqH/s4YlhF6ke1XmUhzksB2eqpNqdgZw1JcZi9droRpuYmIf
+bNyvWqUffHW9mKRv+udF5Woueshn+7Kj9YnnL9jfMzFaVEC8WRwWk54RIdNkxgFq
+dqlaiwBWLvZkNUS9k/nugxVTbNu/GTqQlUG1XsIWBDJ2qRqniRfMKrfBKOxPYCZA
+l7KeFguRA+xOsA7/71OMXJZKneMSWN8duTQCFt7uYCQXWc/IV6BfKTaR/ZQQ4w7/
+iEMYPMZPSNprjun7rx0r2zPZGyrkGSCiS+4e+dfy0NbmYXodGHDxb/vBlm4q8CqF
+OoH9aq0F/3581uZcuvU2ydX/LWcCAwEAAaNQME4wHQYDVR0OBBYEFPK5mwDg7mDV
+fEJs4+ZOP9xvZBHAMB8GA1UdIwQYMBaAFPK5mwDg7mDVfEJs4+ZOP9xvZBHAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKNNP6f0JKxBtfq8hakrhHyl
+cSN83SmVPcrsTLeaW8w0hi+JOtNOjD9sM8KNSbmLXfhRH4yPqYV+0dpJi5+SeelW
+DjxZwbcFoI4EEu+zqufTUpu0T51eqnGvIedlIu1i2CiaoAJEmAN2OKQuN7uIQW27
+2gL/RS+DVkevaidLRh7q2QI23B0n1XZuyEUiUKB1YfTPrupMZkostuyGybAJaxrc
+ONmxUsB38pWJRCef9N/5APS74uIesfxSvEZXcXfPA+wrQY0yXn+bsEhz9pJOxZvD
+WxULUHBC6qH9gAlKEqZYS3CwpCEl/Blznwi30r4CwwQ6dLfeXoPQDxAt7LyPpV4=
\ No newline at end of file
--- /dev/null
+##
+#Host Database
+#
+#localhost is used to configure the loopback interface
+#when the system is booting.Do not change this entry.
+##
+127.0.0.1 localhost
+255.255.255.255 broadcasthost
+::1 localhost
+fe80::1%lo0 localhost