Bump version to upstream-1.3.1
authorsangwan.kwon <sangwan.kwon@samsung.com>
Thu, 30 May 2019 04:31:30 +0000 (13:31 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Wed, 12 Jun 2019 00:04:43 +0000 (09:04 +0900)
- New hash apis

Added: smbios

Signed-off-by: sangwan.kwon <sangwan.kwon@samsung.com>
149 files changed:
include/osquery/config.h
include/osquery/config/plugin.h
include/osquery/core.h
include/osquery/database.h
include/osquery/database/db_handle.h
include/osquery/database/query.h
include/osquery/database/results.h
include/osquery/devtools.h
include/osquery/dispatcher.h
include/osquery/events.h
include/osquery/filesystem.h
include/osquery/flags.h
include/osquery/hash.h [new file with mode: 0644]
include/osquery/logger.h
include/osquery/logger/plugin.h
include/osquery/registry.h
include/osquery/scheduler.h
include/osquery/sql.h
include/osquery/status.h
include/osquery/tables.h
osquery/CMakeLists.txt
osquery/config/CMakeLists.txt
osquery/config/config.cpp
osquery/config/config_tests.cpp
osquery/config/plugins/filesystem.cpp
osquery/config/plugins/glog.cpp [deleted file]
osquery/core/CMakeLists.txt
osquery/core/conversions.cpp [new file with mode: 0644]
osquery/core/conversions.h
osquery/core/conversions_tests.cpp
osquery/core/flags.cpp
osquery/core/hash.cpp [new file with mode: 0644]
osquery/core/hash_tests.cpp [new file with mode: 0644]
osquery/core/init.cpp [moved from osquery/core/init_osquery.cpp with 54% similarity]
osquery/core/md5.h [deleted file]
osquery/core/sql.cpp
osquery/core/sql_tests.cpp
osquery/core/sqlite_util.cpp
osquery/core/sqlite_util.h
osquery/core/sqlite_util_tests.cpp
osquery/core/status_tests.cpp
osquery/core/system.cpp
osquery/core/tables.cpp
osquery/core/tables_tests.cpp [new file with mode: 0644]
osquery/core/test_util.cpp
osquery/core/test_util.h
osquery/core/test_util_tests.cpp
osquery/core/text.cpp
osquery/core/text_tests.cpp
osquery/core/virtual_table.cpp
osquery/core/virtual_table.h
osquery/database/db_handle.cpp
osquery/database/db_handle_tests.cpp
osquery/database/query.cpp
osquery/database/query_tests.cpp
osquery/database/results.cpp
osquery/database/results_tests.cpp
osquery/devtools/printer.cpp
osquery/devtools/printer_tests.cpp
osquery/dispatcher/dispatcher.cpp
osquery/dispatcher/dispatcher_tests.cpp
osquery/events/events.cpp
osquery/events/events_database_tests.cpp
osquery/events/events_tests.cpp
osquery/events/linux/inotify.cpp
osquery/events/linux/inotify.h
osquery/events/linux/inotify_tests.cpp
osquery/events/linux/udev.cpp
osquery/events/linux/udev.h
osquery/filesystem/CMakeLists.txt
osquery/filesystem/filesystem.cpp
osquery/filesystem/filesystem_tests.cpp
osquery/filesystem/linux/mem.cpp [new file with mode: 0644]
osquery/filesystem/linux/proc.cpp
osquery/logger/logger.cpp
osquery/logger/logger_tests.cpp
osquery/logger/plugins/filesystem.cpp
osquery/main/daemon.cpp
osquery/main/lib.cpp
osquery/main/run.cpp [new file with mode: 0644]
osquery/main/shell.cpp
osquery/registry/init_registry.h
osquery/registry/registry_template.h
osquery/registry/registry_tests.cpp
osquery/registry/singleton.h
osquery/scheduler/scheduler.cpp
osquery/scheduler/scheduler_tests.cpp
osquery/tables/CMakeLists.txt
osquery/tables/events/linux/hardware_events.cpp
osquery/tables/events/linux/passwd_changes.cpp
osquery/tables/networking/etc_hosts.cpp
osquery/tables/networking/etc_hosts_tests.cpp
osquery/tables/networking/etc_services.cpp [new file with mode: 0644]
osquery/tables/networking/linux/arp_cache.cpp
osquery/tables/networking/linux/inet_diag.h
osquery/tables/networking/linux/port_inode.cpp [deleted file]
osquery/tables/networking/linux/process_open_sockets.cpp [new file with mode: 0644]
osquery/tables/networking/linux/routes.cpp
osquery/tables/networking/linux/socket_inode.cpp [deleted file]
osquery/tables/networking/listening_ports.cpp [new file with mode: 0644]
osquery/tables/networking/utils.cpp
osquery/tables/networking/utils.h
osquery/tables/specs/blacklist
osquery/tables/specs/linux/port_inode.table [deleted file]
osquery/tables/specs/linux/socket_inode.table [deleted file]
osquery/tables/specs/x/acpi_tables.table [new file with mode: 0644]
osquery/tables/specs/x/etc_services.table [new file with mode: 0644]
osquery/tables/specs/x/hardware_events.table [moved from osquery/tables/specs/linux/hardware_events.table with 92% similarity]
osquery/tables/specs/x/hash.table
osquery/tables/specs/x/listening_ports.table [new file with mode: 0644]
osquery/tables/specs/x/osquery_flags.table [new file with mode: 0644]
osquery/tables/specs/x/osquery_info.table [new file with mode: 0644]
osquery/tables/specs/x/pci_devices.table [new file with mode: 0644]
osquery/tables/specs/x/process_open_files.table
osquery/tables/specs/x/process_open_sockets.table [new file with mode: 0644]
osquery/tables/specs/x/smbios_tables.table [new file with mode: 0644]
osquery/tables/specs/x/usb_devices.table [new file with mode: 0644]
osquery/tables/system/crontab.cpp [moved from osquery/tables/utility/crontab.cpp with 90% similarity]
osquery/tables/system/last.cpp
osquery/tables/system/linux/acpi_tables.cpp [new file with mode: 0644]
osquery/tables/system/linux/groups.cpp
osquery/tables/system/linux/kernel_modules.cpp
osquery/tables/system/linux/mounts.cpp
osquery/tables/system/linux/pci_devices.cpp [new file with mode: 0644]
osquery/tables/system/linux/process_open_files.cpp [new file with mode: 0644]
osquery/tables/system/linux/processes.cpp
osquery/tables/system/linux/smbios_tables.cpp [new file with mode: 0644]
osquery/tables/system/linux/usb_devices.cpp [new file with mode: 0644]
osquery/tables/system/linux/users.cpp
osquery/tables/system/logged_in_users.cpp
osquery/tables/system/shell_history.cpp
osquery/tables/system/smbios_utils.cpp [new file with mode: 0644]
osquery/tables/system/smbios_utils.h [new file with mode: 0644]
osquery/tables/system/suid_bin.cpp
osquery/tables/templates/amalgamation.cpp.in
osquery/tables/templates/blacklist.cpp.in
osquery/tables/templates/default.cpp.in
osquery/tables/utility/file.cpp
osquery/tables/utility/hash.cpp
osquery/tables/utility/osquery.cpp [new file with mode: 0644]
osquery/tables/utility/time.cpp
packaging/osquery.spec
tools/codegen/amalgamate.py [changed mode: 0644->0755]
tools/codegen/gentable.py
tools/deployment/osquery.example.conf [new file with mode: 0644]
tools/tests/test.config [new file with mode: 0644]
tools/tests/test_cert.pem [new file with mode: 0644]
tools/tests/test_hashing.bin [new file with mode: 0644]
tools/tests/test_hosts.txt [new file with mode: 0644]

index d35659d..f3360e7 100644 (file)
@@ -1,46 +1,27 @@
-// 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.
@@ -90,6 +71,13 @@ class Config {
   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}
@@ -106,17 +94,20 @@ class Config {
   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:
   /**
@@ -125,7 +116,7 @@ class Config {
    * 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.
@@ -146,6 +137,26 @@ class Config {
    */
   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
index c1be47b..be04a0c 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 53bfe77..a57080a 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index cab9a46..f0a6109 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 35102d4..1189104 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -237,7 +245,8 @@ class DBHandle {
   /////////////////////////////////////////////////////////////////////////////
 
   friend class DBHandleTests;
-  friend class QueryTests;
+  friend class EventsTests;
   friend class EventsDatabaseTests;
+  friend class QueryTests;
 };
 }
index 93ed2a3..42106f5 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -8,9 +16,9 @@
 
 #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 {
@@ -33,7 +41,7 @@ class Query {
    * @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
index 8a63b65..1a7b3de 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -234,102 +242,6 @@ Status deserializeHistoricalQueryResults(
 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
index b2517f3..3a4c7a9 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 5ea132e..1f79d55 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 108c213..59f0a09 100644 (file)
@@ -1,4 +1,12 @@
-// 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;
@@ -38,8 +49,8 @@ typedef std::pair<EventID, EventTime> EventRecord;
  * 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 {};
@@ -48,8 +59,8 @@ 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 {
@@ -62,184 +73,44 @@ 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.
@@ -266,7 +137,7 @@ struct Subscription {
 
   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;
@@ -275,40 +146,7 @@ struct Subscription {
   }
 };
 
-/**
- * @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
@@ -329,7 +167,7 @@ class EventPublisher {
    * 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.
@@ -345,7 +183,7 @@ class EventPublisher {
    * @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
@@ -356,11 +194,22 @@ class EventPublisher {
    *
    * @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(); }
 
@@ -372,32 +221,121 @@ class EventPublisher {
   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:
   /**
@@ -409,60 +347,214 @@ class EventPublisher {
    *
    * @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.
@@ -492,6 +584,7 @@ class EventSubscriber {
    */
   virtual QueryData get(EventTime start, EventTime stop);
 
+ private:
   /*
    * @brief When `get`ting event results, return EventID%s from time indexes.
    *
@@ -505,7 +598,6 @@ class EventSubscriber {
    */
   std::vector<EventRecord> getRecords(const std::vector<std::string>& indexes);
 
- private:
   /**
    * @brief Get a unique storage-related EventID.
    *
@@ -560,9 +652,9 @@ class EventSubscriber {
    *
    * @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.
    *
@@ -571,18 +663,36 @@ class EventSubscriber {
    * 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; }
 
@@ -601,195 +711,79 @@ class EventSubscriber {
 
  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.
@@ -799,8 +793,8 @@ DECLARE_REGISTRY(EventPublishers, std::string, EventPublisherRef)
  */
 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 {
index 080c815..ceaccb4 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -169,7 +177,7 @@ Status procProcesses(std::vector<std::string>& processes);
  * @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.
@@ -183,5 +191,29 @@ Status procDescriptors(const std::string& process,
 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
 }
index 484222f..7ec812a 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -12,8 +20,8 @@
 
 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.
@@ -30,6 +38,7 @@ class Flag {
    * 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`.
@@ -37,6 +46,7 @@ class Flag {
    * @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);
@@ -45,11 +55,13 @@ class Flag {
    * @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);
@@ -69,7 +81,7 @@ class Flag {
    *
    * @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);
 
@@ -89,6 +101,14 @@ class Flag {
    * @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.
    *
@@ -115,7 +135,7 @@ class Flag {
 #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);      \
   }
 
 /*
@@ -130,5 +150,5 @@ class Flag {
 #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); \
   }
diff --git a/include/osquery/hash.h b/include/osquery/hash.h
new file mode 100644 (file)
index 0000000..b6cc5ae
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  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);
+}
index f283fbd..041191c 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -9,7 +17,7 @@
 #include <glog/logging.h>
 
 #include <osquery/status.h>
-#include <osquery/database.h>
+#include <osquery/scheduler.h>
 
 namespace osquery {
 
@@ -34,7 +42,7 @@ extern const std::string kDefaultLogReceiverName;
  * @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.
@@ -48,7 +56,7 @@ osquery::Status logString(const std::string& s);
  * @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
@@ -58,8 +66,7 @@ osquery::Status logString(const std::string& s, const std::string& 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
@@ -70,6 +77,6 @@ osquery::Status logScheduledQueryLogItem(
  * @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);
 }
index 116bddb..a25a4b3 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 48c6564..4a2461a 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -7,7 +15,8 @@
 #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"
index f01d1b9..1de3183 100644 (file)
-// 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
@@ -18,4 +152,17 @@ namespace osquery {
  * @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);
 }
index 5a117bc..665b153 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 9ed3740..53b5ade 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 157590d..27313a6 100644 (file)
@@ -1,4 +1,12 @@
-// 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 {
 
@@ -52,6 +65,11 @@ 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.
  *
@@ -77,6 +95,12 @@ struct Constraint {
 
   /// 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;
+  }
 };
 
 /**
@@ -90,44 +114,77 @@ struct Constraint {
  * 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);
@@ -149,8 +206,17 @@ struct ConstraintList {
    * @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.
@@ -170,5 +236,37 @@ struct QueryContext {
 
 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;
 }
 }
index c527b91..1a54d8f 100644 (file)
@@ -32,6 +32,7 @@ SET(${TARGET_OSQUERY_LIB}_DEP glog
                                                          boost_system
                                                          boost_thread
                                                          boost_filesystem
+                                                         crypto # openssl
                                                        # shell deps
                                                          readline
                                                        # build-in tables deps
@@ -166,4 +167,3 @@ INSTALL(TARGETS ${TARGET_OSQUERY_DAEMON}
                                        GROUP_EXECUTE
                                        WORLD_READ
                                        WORLD_EXECUTE)
-
index 14419ea..24eed5e 100644 (file)
@@ -1,5 +1,4 @@
 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)
index c46e81d..8d16467 100644 (file)
@@ -1,24 +1,25 @@
-// 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;
 
@@ -29,25 +30,20 @@ DEFINE_osquery_flag(string,
                     "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.
@@ -60,35 +56,46 @@ Config::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;
@@ -117,22 +124,21 @@ std::vector<OsqueryScheduledQuery> Config::getScheduledQueries() {
   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);
 }
 }
index 26d7a54..84d1e04 100644 (file)
@@ -1,31 +1,49 @@
-// 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;
   }
 }
 
@@ -48,26 +66,6 @@ TEST_F(ConfigTests, test_plugin) {
   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[]) {
index ed3ad00..72ca58c 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
@@ -6,6 +14,7 @@
 
 #include <osquery/config/plugin.h>
 #include <osquery/flags.h>
+#include <osquery/logger.h>
 
 namespace fs = boost::filesystem;
 using osquery::Status;
@@ -25,6 +34,7 @@ class FilesystemConfigPlugin : public ConfigPlugin {
       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);
diff --git a/osquery/config/plugins/glog.cpp b/osquery/config/plugins/glog.cpp
deleted file mode 100644 (file)
index e3f1dfe..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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>());
-}
index 986f0cf..f866f50 100644 (file)
@@ -1,4 +1,5 @@
-ADD_OSQUERY_LIBRARY(osquery_core init_osquery.cpp
+ADD_OSQUERY_LIBRARY(osquery_core init.cpp
+                                                                conversions.cpp
                                                                 sql.cpp
                                                                 sqlite_util.cpp
                                                                 system.cpp
@@ -6,11 +7,14 @@ ADD_OSQUERY_LIBRARY(osquery_core init_osquery.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)
diff --git a/osquery/core/conversions.cpp b/osquery/core/conversions.cpp
new file mode 100644 (file)
index 0000000..411cc7e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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();
+}
+}
index 756dc6b..d7d0f3d 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 721063e..6e42e4d 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
index 65ca888..9840be6 100644 (file)
@@ -1,36 +1,53 @@
-// 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.");
   }
@@ -47,10 +64,15 @@ bool Flag::isDefault(const std::string& name) {
   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(), &current_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");
@@ -59,11 +81,10 @@ Status Flag::updateValue(const std::string& name, const std::string& value) {
 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());
   }
 }
 }
diff --git a/osquery/core/hash.cpp b/osquery/core/hash.cpp
new file mode 100644 (file)
index 0000000..5b1b35e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  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();
+}
+}
diff --git a/osquery/core/hash_tests.cpp b/osquery/core/hash_tests.cpp
new file mode 100644 (file)
index 0000000..4c5757e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  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();
+}
similarity index 54%
rename from osquery/core/init_osquery.cpp
rename to osquery/core/init.cpp
index b7fe540..4a96a3a 100644 (file)
@@ -1,10 +1,20 @@
-// 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 {
@@ -31,43 +41,53 @@ DEFINE_osquery_flag(string,
                     "/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;
@@ -107,6 +127,14 @@ void initOsquery(int argc, char* argv[], int tool) {
   }
 
   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();
 }
 }
diff --git a/osquery/core/md5.h b/osquery/core/md5.h
deleted file mode 100644 (file)
index 0f25770..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-// 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;
-  }
-};
-}
-}
index 875458b..e17a50e 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index ef1e866..5d5a946 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index a78ab60..572ee9a 100644 (file)
@@ -1,11 +1,18 @@
-// 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"
 
@@ -28,7 +35,7 @@ QueryData query(const std::string& q, int& error_return) {
 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;
@@ -40,8 +47,6 @@ QueryData query(const std::string& q, int& error_return, sqlite3* db) {
   return d;
 }
 
-namespace core {
-
 int query_data_callback(void* argument,
                         int argc,
                         char* argv[],
@@ -59,4 +64,3 @@ int query_data_callback(void* argument,
   return 0;
 }
 }
-}
index cc8c5bb..c1829f2 100644 (file)
@@ -1,12 +1,18 @@
-// 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[]);
 }
-}
index 3063516..40a187c 100644 (file)
@@ -1,16 +1,23 @@
-// 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 {};
 
@@ -42,7 +49,6 @@ TEST_F(SQLiteUtilTests, test_aggregate_query) {
   EXPECT_EQ(err, 0);
 }
 }
-}
 
 int main(int argc, char* argv[]) {
   testing::InitGoogleTest(&argc, argv);
index b828c2b..0861998 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 1a6470c..1bdbf29 100644 (file)
@@ -1,4 +1,14 @@
-// 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;
@@ -29,8 +38,8 @@ DEFINE_osquery_flag(string,
 
 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;
@@ -45,7 +54,7 @@ std::string generateHostUuid() {
 #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};
@@ -92,51 +101,67 @@ std::vector<fs::path> getHomeDirectories() {
   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;
 }
 }
index 4a2dd92..3d0c3fa 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -7,7 +15,7 @@ namespace osquery {
 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") {
@@ -28,17 +36,17 @@ bool ConstraintList::matches(const std::string& expr) {
 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.
@@ -54,23 +62,13 @@ bool ConstraintList::literal_matches(const T& base_expr) {
 
 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));
-}
 }
 }
diff --git a/osquery/core/tables_tests.cpp b/osquery/core/tables_tests.cpp
new file mode 100644 (file)
index 0000000..8830bc3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  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();
+}
index 2fca252..fc662ff 100644 (file)
@@ -1,23 +1,30 @@
-// 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();
@@ -226,47 +233,14 @@ std::vector<SplitStringTestData> generateSplitStringTestData() {
 }
 
 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;
 }
 
@@ -287,4 +261,3 @@ osquery::QueryData getEtcHostsExpectedResults() {
   return {row1, row2, row3, row4};
 }
 }
-}
index 2a31da7..8590d97 100644 (file)
@@ -1,4 +1,12 @@
-// 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
@@ -87,14 +95,13 @@ std::string getEtcHostsContent();
 // 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();
 }
-}
index d7c0b89..f11f87a 100644 (file)
@@ -1,15 +1,23 @@
-// 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 {};
 
@@ -40,7 +48,6 @@ TEST_F(TestUtilTests, test_get_test_db_result_stream) {
   sqlite3_close(db);
 }
 }
-}
 
 int main(int argc, char* argv[]) {
   testing::InitGoogleTest(&argc, argv);
index 1c0a989..ef56013 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 68e3f16..085398c 100644 (file)
@@ -1,14 +1,21 @@
-// 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 {};
 
@@ -18,7 +25,6 @@ TEST_F(TextTests, test_split) {
   }
 }
 }
-}
 
 int main(int argc, char* argv[]) {
   google::InitGoogleLogging(argv[0]);
index df9aab0..58dd7a7 100644 (file)
@@ -1,6 +1,15 @@
-// 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 {
@@ -67,7 +76,6 @@ std::string TablePlugin::statement(TableName name, TableColumns columns) {
 
 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 << " ("
index 293bf0b..332b1d8 100644 (file)
@@ -1,23 +1,27 @@
-// 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.
  *
@@ -43,38 +47,6 @@ struct x_vtab {
   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);
@@ -155,21 +127,26 @@ int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
 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 autoname =
         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;
 }
 
index 5fc002b..38bff27 100644 (file)
@@ -1,15 +1,23 @@
-// 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 {
index b9d6074..80b9dea 100644 (file)
@@ -1,13 +1,21 @@
-// 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";
 
index f263937..f2ccac5 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 60b44d4..a2f42e0 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -12,8 +20,6 @@
 
 #include "osquery/core/test_util.h"
 
-using namespace osquery::core;
-
 const std::string kTestingQueryDBPath = "/tmp/rocksdb-osquery-querytests";
 
 namespace osquery {
index d7ea05c..251ba85 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -10,9 +18,8 @@
 #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;
index c978b4b..ff81b73 100644 (file)
@@ -1,20 +1,26 @@
-// 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 {};
index fc74a19..31e05ec 100644 (file)
@@ -1,12 +1,19 @@
-// 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 {
 
index 50fb41b..ca59df4 100644 (file)
@@ -1,9 +1,17 @@
-// 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 {
 
index 21cc577..cf8044c 100644 (file)
@@ -1,9 +1,16 @@
-// 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"
 
index 1ade08a..b319b68 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 29d2812..3d05ba0 100644 (file)
@@ -1,4 +1,14 @@
-// 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>
@@ -30,9 +40,14 @@ const std::vector<size_t> kEventTimeLists = {
     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_++;
@@ -54,24 +69,11 @@ void EventPublisher::fire(const EventContextRef ec, EventTime time) {
   }
 
   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();
@@ -81,8 +83,6 @@ std::vector<std::string> EventSubscriber::getIndexes(EventTime start,
   // 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];
@@ -166,7 +166,7 @@ std::vector<std::string> EventSubscriber::getIndexes(EventTime start,
   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) {
@@ -203,7 +203,7 @@ Status EventSubscriber::expireIndexes(
   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();
@@ -234,7 +234,7 @@ std::vector<EventRecord> EventSubscriber::getRecords(
   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);
@@ -290,7 +290,7 @@ Status EventSubscriber::recordEvent(EventID eid, EventTime 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.
@@ -317,10 +317,17 @@ EventID EventSubscriber::getEventID() {
   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);
@@ -352,9 +359,15 @@ QueryData EventSubscriber::get(EventTime start, EventTime 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();
@@ -376,14 +389,14 @@ Status EventSubscriber::add(const Row& r, EventTime time) {
 
 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
@@ -395,20 +408,31 @@ Status EventFactory::run(EventPublisherID type_id) {
   }
 
   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.
@@ -417,35 +441,42 @@ EventFactory& EventFactory::getInstance() {
   return ef;
 }
 
-Status EventFactory::registerEventPublisher(const EventPublisherRef event_pub) {
+Status EventFactory::registerEventPublisher(const EventPublisherRefpub) {
   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.
@@ -458,14 +489,7 @@ Status EventFactory::addSubscription(EventPublisherID 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) {
@@ -474,8 +498,7 @@ size_t EventFactory::numSubscriptions(EventPublisherID type_id) {
   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()) {
@@ -484,12 +507,21 @@ std::shared_ptr<EventPublisher> EventFactory::getEventPublisher(
   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()) {
index b189b91..6b34693 100644 (file)
@@ -1,4 +1,12 @@
-// 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() {
@@ -22,8 +28,13 @@ class EventsDatabaseTests : public ::testing::Test {
   }
 };
 
-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
@@ -34,118 +45,102 @@ class FakeEventSubscriber : public EventSubscriber {
   }
 };
 
-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
 }
 }
@@ -153,6 +148,6 @@ TEST_F(EventsDatabaseTests, test_record_expiration) {
 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;
 }
index 974f482..7219ea3 100644 (file)
@@ -1,4 +1,16 @@
-// 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) {
@@ -80,20 +130,19 @@ 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() {
@@ -133,65 +182,58 @@ class TestEventPublisher : public EventPublisher {
 };
 
 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);
@@ -199,42 +241,121 @@ TEST_F(EventsTests, test_tear_down) {
 
 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;
 }
index 7927bb1..be25d45 100644 (file)
@@ -1,13 +1,20 @@
-// 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"
 
@@ -97,7 +104,7 @@ Status INotifyEventPublisher::run() {
       // 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
@@ -108,7 +115,7 @@ Status INotifyEventPublisher::run() {
   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();
@@ -132,8 +139,8 @@ INotifyEventContextRef INotifyEventPublisher::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;
index 0be6b06..502f900 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -44,7 +52,7 @@ struct INotifySubscriptionContext : public SubscriptionContext {
    *
    * @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;
@@ -86,10 +94,9 @@ typedef std::map<int, std::string> DescriptorPathMap;
  * 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.
@@ -105,7 +112,7 @@ class INotifyEventPublisher : public EventPublisher {
   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.
@@ -114,8 +121,8 @@ class INotifyEventPublisher : public EventPublisher {
   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.
index a71b3e9..b51793e 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
@@ -166,22 +174,22 @@ TEST_F(INotifyTests, test_inotify_run) {
   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);
@@ -189,10 +197,17 @@ class TestINotifyEventSubscriber : public EventSubscriber {
     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);
@@ -200,9 +215,9 @@ class TestINotifyEventSubscriber : public EventSubscriber {
     }
   }
 
-  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_;
@@ -212,17 +227,18 @@ class TestINotifyEventSubscriber : public EventSubscriber {
 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();
@@ -231,17 +247,18 @@ TEST_F(INotifyTests, test_inotify_fire_event) {
 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();
@@ -268,23 +285,24 @@ TEST_F(INotifyTests, test_inotify_optimization) {
 
 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();
 }
index 4762b1d..81095f2 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -59,7 +67,7 @@ Status UdevEventPublisher::run() {
     return Status(1, "udev monitor failed.");
   }
 
-  auto ec = createEventContext(device);
+  auto ec = createEventContextFrom(device);
   fire(ec);
 
   udev_device_unref(device);
@@ -70,15 +78,23 @@ Status UdevEventPublisher::run() {
 
 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;
@@ -117,8 +133,8 @@ UdevEventContextRef UdevEventPublisher::createEventContext(
   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;
index 215bd87..1544a12 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
@@ -61,10 +69,9 @@ typedef std::shared_ptr<UdevSubscriptionContext> UdevSubscriptionContextRef;
  * @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();
@@ -73,18 +80,31 @@ class UdevEventPublisher : public EventPublisher {
 
   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_;
@@ -92,9 +112,9 @@ class UdevEventPublisher : public EventPublisher {
 
  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);
 };
 }
index 96d9a40..c07d505 100644 (file)
@@ -1,5 +1,6 @@
 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)
index d856bfb..f795963 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -12,9 +20,8 @@
 #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;
index eab0d7d..2d8f47e 100644 (file)
@@ -1,15 +1,24 @@
-// 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;
 
diff --git a/osquery/filesystem/linux/mem.cpp b/osquery/filesystem/linux/mem.cpp
new file mode 100644 (file)
index 0000000..ce02e30
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  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");
+}
+}
index ef46ea5..3c28579 100644 (file)
@@ -1,15 +1,24 @@
-// 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 {
 
@@ -39,13 +48,17 @@ Status procProcesses(std::vector<std::string>& processes) {
 }
 
 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);
index dfa7af1..e34aae1 100644 (file)
@@ -1,10 +1,16 @@
-// 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>
index cdcc026..adaa945 100644 (file)
@@ -1,7 +1,14 @@
-// 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>
index c35446c..8eeefdb 100644 (file)
@@ -1,12 +1,19 @@
-// 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;
index 85fa72e..c2aa818 100644 (file)
@@ -1,23 +1,60 @@
-// 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);
   }
 
@@ -25,7 +62,7 @@ int main(int argc, char* argv[]) {
     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";
index 9e5c076..45f5188 100644 (file)
@@ -1,5 +1,13 @@
-// 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>
diff --git a/osquery/main/run.cpp b/osquery/main/run.cpp
new file mode 100644 (file)
index 0000000..0baa745
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  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;
+}
index cbd890f..c6d3b61 100644 (file)
@@ -1,5 +1,13 @@
-// 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>
index 001fda9..af3ba2a 100644 (file)
@@ -1,5 +1,13 @@
-// 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>
index 0149641..de413b6 100644 (file)
@@ -1,5 +1,13 @@
-// 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>
index 4807ecf..a132904 100644 (file)
@@ -1,13 +1,21 @@
-// 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"; }
index b4d0e2d..16f53a3 100644 (file)
@@ -1,5 +1,13 @@
-// 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 {
index 5450001..6aa9142 100644 (file)
@@ -1,9 +1,16 @@
-// 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>
@@ -20,11 +27,16 @@ DEFINE_osquery_flag(string,
                     "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());
   }
 
@@ -61,67 +73,92 @@ Status getHostIdentifier(std::string& ident) {
   }
 }
 
+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;
@@ -129,9 +166,22 @@ void initializeScheduler() {
   // 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);
   }
 }
 }
index 05f79e9..1bf289e 100644 (file)
@@ -1,13 +1,44 @@
-// 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();
index 2303576..2433134 100644 (file)
@@ -1,21 +1,29 @@
 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
index 3a9c5eb..5eedb20 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -15,26 +23,25 @@ namespace tables {
 /**
  * @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()) {
@@ -51,17 +58,19 @@ Status HardwareEventSubscriber::Callback(const UdevEventContextRef ec) {
   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);
index 687fbfe..0cf5965 100644 (file)
@@ -1,12 +1,20 @@
-// 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 {
@@ -17,9 +25,9 @@ namespace tables {
  *
  * 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();
@@ -32,7 +40,7 @@ class PasswdChangesEventSubscriber : public EventSubscriber {
    *
    * @return Was the callback successful.
    */
-  Status Callback(const INotifyEventContextRef ec);
+  Status Callback(const INotifyEventContextRef& ec);
 };
 
 /**
@@ -45,13 +53,14 @@ class PasswdChangesEventSubscriber : public EventSubscriber {
 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;
index 08b19c5..eaba8ac 100644 (file)
@@ -1,4 +1,12 @@
-// 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 {
index 70320ff..637ba9c 100644 (file)
@@ -1,12 +1,19 @@
-// 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 {
diff --git a/osquery/tables/networking/etc_services.cpp b/osquery/tables/networking/etc_services.cpp
new file mode 100644 (file)
index 0000000..2873a5d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  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 {};
+  }
+}
+}
+}
index 3e67227..e5a3a60 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index ea9ed50..65b5d9e 100644 (file)
@@ -1,3 +1,13 @@
+/*
+ *  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_
 
diff --git a/osquery/tables/networking/linux/port_inode.cpp b/osquery/tables/networking/linux/port_inode.cpp
deleted file mode 100644 (file)
index 9b66788..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-// 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;
-}
-}
-}
diff --git a/osquery/tables/networking/linux/process_open_sockets.cpp b/osquery/tables/networking/linux/process_open_sockets.cpp
new file mode 100644 (file)
index 0000000..de083fa
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  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;
+}
+}
+}
index 2bb512d..a0ab1bb 100644 (file)
@@ -1,9 +1,12 @@
-// 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);
 
@@ -34,20 +38,29 @@ std::string netlink_ip(int family, const char* buffer) {
   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) {
@@ -62,28 +75,23 @@ int read_netlink(int socket_fd, char* output, int seq) {
     }
   } 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) {
@@ -92,18 +100,18 @@ void genNetlinkRoutes(const struct nlmsghdr* netlink_msg, QueryData& results) {
       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;
@@ -147,20 +155,20 @@ void genNetlinkRoutes(const struct nlmsghdr* netlink_msg, QueryData& results) {
 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;
@@ -169,15 +177,19 @@ QueryData genRoutes(QueryContext& context) {
 
   // 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
@@ -186,12 +198,8 @@ QueryData genRoutes(QueryContext& context) {
     netlink_msg = NLMSG_NEXT(netlink_msg, size);
   }
 
-cleanup:
   close(socket_fd);
-  if (netlink_buffer != NULL) {
-    free(netlink_buffer);
-  }
-
+  free(netlink_buffer);
   return results;
 }
 }
diff --git a/osquery/tables/networking/linux/socket_inode.cpp b/osquery/tables/networking/linux/socket_inode.cpp
deleted file mode 100644 (file)
index 36967af..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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;
-}
-}
-}
diff --git a/osquery/tables/networking/listening_ports.cpp b/osquery/tables/networking/listening_ports.cpp
new file mode 100644 (file)
index 0000000..951163a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  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;
+}
+}
+}
index d7478a0..0b92052 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
index 6e6f2a7..58a65b2 100644 (file)
@@ -1,4 +1,12 @@
-// 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
 
index 1027de0..376bf40 100644 (file)
@@ -3,4 +3,3 @@
 # Example: add tables that are not yet ready for release
 
 quarantine
-suid_bin
diff --git a/osquery/tables/specs/linux/port_inode.table b/osquery/tables/specs/linux/port_inode.table
deleted file mode 100644 (file)
index b4deb35..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-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")
-
diff --git a/osquery/tables/specs/linux/socket_inode.table b/osquery/tables/specs/linux/socket_inode.table
deleted file mode 100644 (file)
index 92b156a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-table_name("socket_inode")
-schema([
-    Column("pid", TEXT),
-    Column("inode", TEXT),
-])
-implementation("osquery/tables/networking/linux/socket_inode@genSocketInode")
diff --git a/osquery/tables/specs/x/acpi_tables.table b/osquery/tables/specs/x/acpi_tables.table
new file mode 100644 (file)
index 0000000..1ed8290
--- /dev/null
@@ -0,0 +1,7 @@
+table_name("acpi_tables")
+schema([
+    Column("name", TEXT),
+    Column("size", INTEGER),
+    Column("md5", TEXT),
+])
+implementation("system/acpi_tables@genACPITables")
diff --git a/osquery/tables/specs/x/etc_services.table b/osquery/tables/specs/x/etc_services.table
new file mode 100644 (file)
index 0000000..64599d4
--- /dev/null
@@ -0,0 +1,11 @@
+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")
+
@@ -8,7 +8,7 @@ schema([
     Column("model_id", INTEGER),
     Column("vendor", TEXT),
     Column("vendor_id", INTEGER),
-    Column("serial", INTEGER),
+    Column("serial", TEXT),
     Column("revision", INTEGER),
     Column("time", INTEGER),
 ])
index f20478e..6a8f38c 100644 (file)
@@ -3,5 +3,7 @@ schema([
     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")
diff --git a/osquery/tables/specs/x/listening_ports.table b/osquery/tables/specs/x/listening_ports.table
new file mode 100644 (file)
index 0000000..c883ca4
--- /dev/null
@@ -0,0 +1,9 @@
+table_name("listening_ports")
+schema([
+    Column("pid", INTEGER),
+    Column("port", INTEGER),
+    Column("protocol", INTEGER),
+    Column("family", INTEGER),
+    Column("address", TEXT),
+])
+implementation("listening_ports@genListeningPorts")
diff --git a/osquery/tables/specs/x/osquery_flags.table b/osquery/tables/specs/x/osquery_flags.table
new file mode 100644 (file)
index 0000000..18b907d
--- /dev/null
@@ -0,0 +1,10 @@
+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")
diff --git a/osquery/tables/specs/x/osquery_info.table b/osquery/tables/specs/x/osquery_info.table
new file mode 100644 (file)
index 0000000..b55d0bb
--- /dev/null
@@ -0,0 +1,8 @@
+table_name("osquery_info")
+schema([
+    Column("version", TEXT),
+    Column("config_md5", TEXT),
+    Column("config_path", TEXT),
+    Column("pid", INTEGER),
+])
+implementation("osquery@genOsqueryInfo")
diff --git a/osquery/tables/specs/x/pci_devices.table b/osquery/tables/specs/x/pci_devices.table
new file mode 100644 (file)
index 0000000..472bd92
--- /dev/null
@@ -0,0 +1,17 @@
+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")
index 605bb88..8ab3625 100644 (file)
@@ -1,11 +1,7 @@
 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")
diff --git a/osquery/tables/specs/x/process_open_sockets.table b/osquery/tables/specs/x/process_open_sockets.table
new file mode 100644 (file)
index 0000000..5983369
--- /dev/null
@@ -0,0 +1,13 @@
+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")
+
diff --git a/osquery/tables/specs/x/smbios_tables.table b/osquery/tables/specs/x/smbios_tables.table
new file mode 100644 (file)
index 0000000..94c01ee
--- /dev/null
@@ -0,0 +1,11 @@
+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")
diff --git a/osquery/tables/specs/x/usb_devices.table b/osquery/tables/specs/x/usb_devices.table
new file mode 100644 (file)
index 0000000..58c2afb
--- /dev/null
@@ -0,0 +1,12 @@
+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")
similarity index 90%
rename from osquery/tables/utility/crontab.cpp
rename to osquery/tables/system/crontab.cpp
index bf117dd..60cd624 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 44e9a39..0d8707c 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
diff --git a/osquery/tables/system/linux/acpi_tables.cpp b/osquery/tables/system/linux/acpi_tables.cpp
new file mode 100644 (file)
index 0000000..8ca85db
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  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;
+}
+}
+}
index dd2e082..6883c4a 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
index ee0097f..f3fadad 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
@@ -19,15 +27,15 @@ QueryData genKernelModules(QueryContext& context) {
   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),
@@ -36,7 +44,6 @@ QueryData genKernelModules(QueryContext& context) {
   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;
index a8c4c9a..d4b804c 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
diff --git a/osquery/tables/system/linux/pci_devices.cpp b/osquery/tables/system/linux/pci_devices.cpp
new file mode 100644 (file)
index 0000000..8a07587
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  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;
+}
+}
+}
diff --git a/osquery/tables/system/linux/process_open_files.cpp b/osquery/tables/system/linux/process_open_files.cpp
new file mode 100644 (file)
index 0000000..1e6a571
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  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;
+}
+}
+}
index ed30411..0664210 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
@@ -8,6 +16,8 @@
 #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>
@@ -26,11 +36,7 @@ namespace tables {
 #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) {
@@ -142,7 +148,9 @@ QueryData genProcesses(QueryContext& context) {
     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();
 
@@ -189,10 +197,5 @@ QueryData genProcessEnvs(QueryContext& context) {
 
   return results;
 }
-
-QueryData genProcessOpenFiles(QueryContext& context) {
-  QueryData results;
-  return results;
-}
 }
 }
diff --git a/osquery/tables/system/linux/smbios_tables.cpp b/osquery/tables/system/linux/smbios_tables.cpp
new file mode 100644 (file)
index 0000000..890ec2f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  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;
+}
+}
+}
diff --git a/osquery/tables/system/linux/usb_devices.cpp b/osquery/tables/system/linux/usb_devices.cpp
new file mode 100644 (file)
index 0000000..476e87b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  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;
+}
+}
+}
index 363807f..a2e61ed 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
index a004dec..bb613be 100644 (file)
@@ -1,5 +1,12 @@
-// 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>
 
index e078352..fde7543 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
diff --git a/osquery/tables/system/smbios_utils.cpp b/osquery/tables/system/smbios_utils.cpp
new file mode 100644 (file)
index 0000000..4e0ba4c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  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);
+  }
+}
+}
+}
diff --git a/osquery/tables/system/smbios_utils.h b/osquery/tables/system/smbios_utils.h
new file mode 100644 (file)
index 0000000..ff5eea3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  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);
+}
+}
index e4c70a1..43811e6 100644 (file)
@@ -1,23 +1,39 @@
-// 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) {
@@ -27,7 +43,6 @@ Status genBin(const boost::filesystem::path& path,
   // store path
   Row r;
   r["path"] = path.string();
-
   struct passwd *pw = getpwuid(info.st_uid);
   struct group *gr = getgrgid(info.st_gid);
 
@@ -62,44 +77,56 @@ Status genBin(const boost::filesystem::path& path,
   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;
 }
index 3505ca4..fddd400 100644 (file)
@@ -1,10 +1,20 @@
-// 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 {
index 68a3f14..ab071d7 100644 (file)
@@ -1,4 +1,12 @@
-// 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!
index fe37dcd..108103f 100644 (file)
@@ -1,10 +1,20 @@
-// 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 {
@@ -15,7 +25,7 @@ osquery::QueryData {{function}}(QueryContext& request);
 {% else %}
 class {{class_name}} {
  public:
-  static osquery::QueryData {{function}}(QueryContext& request);
+  osquery::QueryData {{function}}(QueryContext& request);
 };
 {% endif %}\
 
@@ -31,7 +41,8 @@ public:
 
   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 %}\
index 103fa00..73e84ae 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 10f9598..ad5bec7 100644 (file)
@@ -1,18 +1,24 @@
-// 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) {
@@ -20,10 +26,13 @@ QueryData genHash(QueryContext& context) {
     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);
   }
 
@@ -41,7 +50,11 @@ QueryData genHash(QueryContext& context) {
       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);
     }
diff --git a/osquery/tables/utility/osquery.cpp b/osquery/tables/utility/osquery.cpp
new file mode 100644 (file)
index 0000000..7eea475
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  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;
+}
+}
+}
index 40730e2..3be3f39 100644 (file)
@@ -1,4 +1,12 @@
-// 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>
 
index 6e8e88a..3a80eaa 100644 (file)
@@ -1,5 +1,5 @@
 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.
@@ -23,6 +23,7 @@ BuildRequires: thrift
 BuildRequires: readline-devel
 BuildRequires: pkgconfig(libprocps)
 BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(openssl)
 BuildRequires: python-jinja2
 Requires: glog
 Requires: gflag
@@ -73,6 +74,7 @@ Testcases for osquery
 
 %files test
 %manifest %{name}.manifest
+%{_bindir}/osquery_hash_tests
 %{_bindir}/osquery_status_tests
 %{_bindir}/osquery_db_handle_tests
 %{_bindir}/osquery_results_tests
@@ -82,6 +84,7 @@ Testcases for osquery
 %{_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
old mode 100644 (file)
new mode 100755 (executable)
index df6763c..3d47df0
@@ -1,5 +1,11 @@
 #!/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
index ae18fb4..09804c1 100755 (executable)
@@ -1,5 +1,11 @@
 #!/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
@@ -22,7 +28,7 @@ LOG_FORMAT = "%(levelname)s [Line %(lineno)d]: %(message)s"
 TEMPLATES = {}
 
 # Temporary reserved column names
-RESERVED = ["n"]
+RESERVED = ["n", "index"]
 
 # Supported SQL types for spec
 
@@ -159,7 +165,11 @@ class TableState(Singleton):
             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)
diff --git a/tools/deployment/osquery.example.conf b/tools/deployment/osquery.example.conf
new file mode 100644 (file)
index 0000000..c326005
--- /dev/null
@@ -0,0 +1,71 @@
+{
+  /* 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
+    }
+  ]
+}
diff --git a/tools/tests/test.config b/tools/tests/test.config
new file mode 100644 (file)
index 0000000..d1b10e9
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scheduledQueries": [
+    {
+      "name": "time",
+      "query": "select * from time;",
+      "interval": 1
+    }
+  ]
+}
diff --git a/tools/tests/test_cert.pem b/tools/tests/test_cert.pem
new file mode 100644 (file)
index 0000000..48c9ea1
--- /dev/null
@@ -0,0 +1,23 @@
+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
diff --git a/tools/tests/test_hashing.bin b/tools/tests/test_hashing.bin
new file mode 100644 (file)
index 0000000..e80db2c
Binary files /dev/null and b/tools/tests/test_hashing.bin differ
diff --git a/tools/tests/test_hosts.txt b/tools/tests/test_hosts.txt
new file mode 100644 (file)
index 0000000..5ff5a66
--- /dev/null
@@ -0,0 +1,10 @@
+##
+#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