Merge pull request #697 from theopolis/sdk_step1

Organizing headers/build for SDK
This commit is contained in:
Teddy Reed 2015-02-03 19:47:14 -08:00
commit a4689bc241
48 changed files with 950 additions and 816 deletions

View File

@ -6,7 +6,6 @@
# osquery-specific helper macros
macro(SET_OSQUERY_COMPILE TARGET)
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${OS_COMPILE_FLAGS})
set(OPTIONAL_FLAGS ${ARGN})
list(LENGTH OPTIONAL_FLAGS NUM_OPTIONAL_FLAGS)
if(${NUM_OPTIONAL_FLAGS} GREATER 0)
@ -14,12 +13,12 @@ macro(SET_OSQUERY_COMPILE TARGET)
endif()
endmacro(SET_OSQUERY_COMPILE)
macro(ADD_OSQUERY_TEST TEST_NAME SOURCE)
if(NOT DEFINED ENV{SKIP_TESTS})
macro(ADD_OSQUERY_TEST IS_CORE TEST_NAME SOURCE)
if(NOT DEFINED ENV{SKIP_TESTS} AND (${IS_CORE} OR NOT OSQUERY_BUILD_SDK_ONLY))
add_executable(${TEST_NAME} ${SOURCE})
TARGET_OSQUERY_LINK_WHOLE(${TEST_NAME} libosquery_basic)
set(TEST_FLAGS ${ARGN})
if(${TEST_FLAGS})
TARGET_OSQUERY_LINK_WHOLE(${TEST_NAME} libosquery)
set(TEST_LINK_ADDITIONAL ${ARGN})
if(NOT ${IS_CORE})
target_link_libraries(${TEST_NAME} libosquery_additional)
endif()
target_link_libraries(${TEST_NAME} gtest)
@ -29,14 +28,14 @@ macro(ADD_OSQUERY_TEST TEST_NAME SOURCE)
endmacro(ADD_OSQUERY_TEST)
# Core/non core link helping macros (tell the build to link ALL).
macro(ADD_OSQUERY_LINK LINK)
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_ADDITIONAL_LINKS)
macro(ADD_OSQUERY_LINK IS_CORE LINK)
if(${IS_CORE})
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_LINKS)
elseif(NOT OSQUERY_BUILD_SDK_ONLY)
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_ADDITIONAL_LINKS)
endif()
endmacro(ADD_OSQUERY_LINK)
macro(ADD_OSQUERY_CORE_LINK LINK)
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_LINKS)
endmacro(ADD_OSQUERY_CORE_LINK)
macro(ADD_OSQUERY_LINK_INTERNAL LINK LINK_PATHS LINK_SET)
if(NOT "${LINK}" MATCHES "(^-.*)")
find_library("${LINK}_library" NAMES "lib${LINK}.a" "${LINK}" ${LINK_PATHS})
@ -55,39 +54,37 @@ macro(ADD_OSQUERY_LINK_INTERNAL LINK LINK_PATHS LINK_SET)
endmacro(ADD_OSQUERY_LINK_INTERNAL)
# Core/non core lists of target source files.
macro(ADD_OSQUERY_LIBRARY TARGET)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET})
list(APPEND OSQUERY_ADDITIONAL_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_ADDITIONAL_SOURCES ${OSQUERY_ADDITIONAL_SOURCES} PARENT_SCOPE)
macro(ADD_OSQUERY_LIBRARY IS_CORE TARGET)
if(${IS_CORE} OR NOT OSQUERY_BUILD_SDK_ONLY)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET} "-static")
if(${IS_CORE})
list(APPEND OSQUERY_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
else()
list(APPEND OSQUERY_ADDITIONAL_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_ADDITIONAL_SOURCES ${OSQUERY_ADDITIONAL_SOURCES} PARENT_SCOPE)
endif()
endif()
endmacro(ADD_OSQUERY_LIBRARY TARGET)
macro(ADD_OSQUERY_CORE_LIBRARY TARGET)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET})
list(APPEND OSQUERY_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
endmacro(ADD_OSQUERY_CORE_LIBRARY TARGET)
# Core/non core lists of target source files compiled as ObjC++.
macro(ADD_OSQUERY_OBJCXX_LIBRARY TARGET)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET} "${OBJCXX_COMPILE_FLAGS}")
list(APPEND OSQUERY_ADDITIONAL_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_ADDITIONAL_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
macro(ADD_OSQUERY_OBJCXX_LIBRARY IS_CORE TARGET)
if(${IS_CORE} OR NOT OSQUERY_BUILD_SDK_ONLY)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET} "${C_COMPILE_FLAGS} ${OBJCXX_COMPILE_FLAGS} -static")
if(${IS_CORE})
list(APPEND OSQUERY_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
else()
list(APPEND OSQUERY_ADDITIONAL_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_ADDITIONAL_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
endif()
endif()
endmacro(ADD_OSQUERY_OBJCXX_LIBRARY TARGET)
macro(ADD_OSQUERY_CORE_OBJCXX_LIBRARY TARGET)
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} libglog)
SET_OSQUERY_COMPILE(${TARGET} "${OBJCXX_COMPILE_FLAGS}")
list(APPEND OSQUERY_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
endmacro(ADD_OSQUERY_CORE_OBJCXX_LIBRARY TARGET)
# Helper to abstract OS/Compiler whole linking.
macro(TARGET_OSQUERY_LINK_WHOLE TARGET OSQUERY_LIB)
target_link_libraries(${TARGET} "${OS_WHOLELINK_PRE}")

View File

@ -1,4 +1,7 @@
include(FindPackageHandleStandardArgs)
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
set(GLOG_ROOT_DIR "${CMAKE_BINARY_DIR}/third-party/glog")
set(GLOG_SOURCE_DIR "${CMAKE_SOURCE_DIR}/third-party/glog")
@ -17,7 +20,7 @@ if(NOT APPLE)
endif()
endif()
set(GLOG_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unnamed-type-template-args")
set(GLOG_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unnamed-type-template-args -DHAVE_PREAD")
INCLUDE(ExternalProject)
ExternalProject_Add(
@ -32,6 +35,7 @@ ExternalProject_Add(
INSTALL_COMMAND make install
LOG_CONFIGURE ON
LOG_INSTALL ON
LOG_BUILD ON
)
set(GLOG_INCLUDE_DIR "${GLOG_ROOT_DIR}/include")

55
CMake/Packages.cmake Normal file
View File

@ -0,0 +1,55 @@
# make package
if(APPLE)
add_custom_target(
packages
"${CMAKE_SOURCE_DIR}/tools/deployment/make_osx_package.sh"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Building default OS X package (no custom config)" VERBATIM
)
elseif(LINUX)
if(UBUNTU)
set(PACKAGE_TYPE "deb")
set(PACKAGE_DEPENDENCIES
"libc6 (>=2.15)"
"zlib1g"
"libbz2-1.0"
"libapt-pkg4.12"
"libreadline6"
)
if(OSQUERY_BUILD_DISTRO STREQUAL "PRECISE")
set(PACKAGE_DEPENDENCIES
"${PACKAGE_DEPENDENCIES}"
"libstdc++6"
"libudev0"
)
elseif(OSQUERY_BUILD_DISTRO STREQUAL "TRUSTY")
set(PACKAGE_DEPENDENCIES
"${PACKAGE_DEPENDENCIES}"
"libstdc++6 (>= 4.8)"
"libudev1"
)
endif()
elseif(CENTOS)
set(PACKAGE_TYPE "rpm")
set(PACKAGE_DEPENDENCIES
"glibc >= 2.12"
"openssl >= 1.0"
"readline"
"zlib"
"snappy"
"bzip2-libs"
"procps"
"libudev"
"rpm-libs"
)
endif()
JOIN("${PACKAGE_DEPENDENCIES}" ", " PACKAGE_DEPENDENCIES)
add_custom_target(
packages
"${CMAKE_SOURCE_DIR}/tools/deployment/make_linux_package.sh"
-t ${PACKAGE_TYPE} -d "${PACKAGE_DEPENDENCIES}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Building linux packages (no custom config)" VERBATIM
)
endif()

View File

@ -4,47 +4,52 @@ set(CMAKE_C_COMPILER "/usr/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
if(APPLE)
set(APPLE_MIN_ABI "10.9")
set(OS_COMPILE_FLAGS "-std=c++11 -stdlib=libc++ -mmacosx-version-min=${APPLE_MIN_ABI}")
# Special compile flags for Objective-C++
set(OBJCXX_COMPILE_FLAGS "-x objective-c++ -fobjc-arc -Wno-c++11-extensions")
set(CXX_COMPILE_FLAGS "${CXX_COMPILE_FLAGS} -std=c++11 -stdlib=libc++")
set(CXX_COMPILE_FLAGS "${CXX_COMPILE_FLAGS} -mmacosx-version-min=${APPLE_MIN_ABI}")
set(OS_WHOLELINK_PRE "-Wl,-force_load")
set(OS_WHOLELINK_POST "")
# Special compile flags for Objective-C++
set(OBJCXX_COMPILE_FLAGS "-x objective-c++ -fobjc-arc -Wno-c++11-extensions")
else()
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(FREEBSD TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
set(CXX_COMPILE_FLAGS "${CXX_COMPILE_FLAGS} -std=c++11 -stdlib=libc++")
set(OS_WHOLELINK_PRE "")
set(OS_WHOLELINK_POST "")
else()
set(LINUX TRUE)
set(CMAKE_C_FLAGS "-fno-omit-frame-pointer")
set(OS_COMPILE_FLAGS "-std=c++11")
set(CXX_COMPILE_FLAGS "-std=c++11")
set(OS_WHOLELINK_PRE "-Wl,-whole-archive")
set(OS_WHOLELINK_POST "-Wl,-no-whole-archive")
endif()
endif()
# make debug (environment variable from Makefile)
if(DEFINED ENV{DEBUG})
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -DDEBUG -O0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -DDEBUG -O0")
set(C_COMPILE_FLAGS "${CMAKE_C_FLAGS} -g -DDEBUG -O0")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
set(C_COMPILE_FLAGS "${CMAKE_C_FLAGS} -O2")
endif()
# make analyze (environment variable from Makefile)
if(DEFINED ENV{ANALYZE})
set(CMAKE_CXX_COMPILER "${CMAKE_SOURCE_DIR}/tools/analysis/clang-analyze.sh")
endif()
# make sanitize (environment variable from Makefile)
if(DEFINED ENV{SANITIZE})
set(CMAKE_CXX_FLAGS "-g -O0 -fno-omit-frame-pointer")
set(OS_COMPILE_FLAGS "${OS_COMPILE_FLAGS} -fsanitize=leak -fsanitize=address")
set(CXX_COMPILE_FLAGS "-g -O0 -fno-omit-frame-pointer")
set(CXX_COMPILE_FLAGS "${CXX_COMPILE_FLAGS} -fsanitize=leak -fsanitize=address")
if(LINUX)
set(CMAKE_CXX_FLAGS "${OS_COMPILE_FLAGS} -fsanitize=memory")
set(CXX_COMPILE_FLAGS "${CXX_COMPILE_FLAGS} -fsanitize=memory")
endif()
endif()
# Finished setting compiler/compiler flags.
set(CMAKE_CXX_FLAGS "${C_COMPILE_FLAGS} ${CXX_COMPILE_FLAGS}"
CACHE STRING "compile flags" FORCE)
project(OSQUERY)
# Use osquery language to set platform/os
@ -59,7 +64,7 @@ string(TOUPPER "${PLATFORM}" PLATFORM)
list(GET PLATFORM 0 OSQUERY_BUILD_OS)
list(GET PLATFORM 1 OSQUERY_BUILD_DISTRO)
# Make sure deps were built before compiling
# Make sure deps were built before compiling (else show warning)
execute_process(
COMMAND "${CMAKE_SOURCE_DIR}/tools/provision.sh" check "${CMAKE_BINARY_DIR}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@ -67,28 +72,47 @@ execute_process(
RESULT_VARIABLE OSQUERY_DEPS_CHECK
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(ASCII 27 Esc)
if(OSQUERY_DEPS_CHECK)
message(WARNING "${Esc}[31m${OSQUERY_DEPS_MESSAGE}${Esc}[m")
endif()
# Generate version from git
execute_process(
COMMAND git describe --tags HEAD --always
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE OSQUERY_BUILD_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# make extensions (tests building SDK-based extensions)
if(DEFINED ENV{SDK})
set(OSQUERY_BUILD_SDK_ONLY TRUE)
add_definitions(
-DOSQUERY_BUILD_SDK
-DOSQUERY_BUILD_SDK_VERSION=${OSQUERY_BUILD_VERSION}
)
endif()
# Set various platform/platform-version/build version/etc defines.
add_definitions(
-DOSQUERY_BUILD_VERSION=${OSQUERY_BUILD_VERSION}
-D${OSQUERY_BUILD_OS}
-D${OSQUERY_BUILD_OS}_${OSQUERY_BUILD_DISTRO}
)
if(APPLE)
message("-- Building for OS X")
elseif(OSQUERY_BUILD_OS STREQUAL "UBUNTU")
set(LINUX TRUE)
set(UBUNTU TRUE)
message("-- Building for Ubuntu")
elseif(OSQUERY_BUILD_OS STREQUAL "CENTOS")
set(LINUX TRUE)
set(CENTOS TRUE)
message("-- Building for CentOS")
elseif(FREEBSD)
message("-- Building for FreeBSD")
endif()
set(USER_COMPILE_FLAGS "-static")
set(OS_COMPILE_FLAGS "${OS_COMPILE_FLAGS} ${USER_COMPILE_FLAGS}")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" "${CMAKE_MODULE_PATH}")
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE)
@ -119,6 +143,7 @@ link_directories("/usr/local/lib")
enable_testing()
include(CMakeLibs)
include(Packages)
add_subdirectory(osquery)
# make docs
@ -140,6 +165,7 @@ add_custom_target(
COMMENT "Formatting all osquery code with clang-format" VERBATIM
)
# make format
add_custom_target(
format
python "${CMAKE_SOURCE_DIR}/tools/formatting/git-clang-format.py"

View File

@ -31,6 +31,14 @@ sanitize: .setup
cd build/$(BUILD_DIR) && SANITIZE=True cmake ../../ && \
$(MAKE) --no-print-directory $(MAKEFLAGS)
sdk: .setup
cd build/$(BUILD_DIR) && SDK=True cmake ../../ && \
$(MAKE) --no-print-directory $(MAKEFLAGS)
test_sdk: .setup
cd build/$(BUILD_DIR) && SDK=True cmake ../../ && \
$(MAKE) test --no-print-directory $(MAKEFLAGS)
deps: .setup
./tools/provision.sh build build/$(BUILD_DIR)

View File

@ -14,9 +14,6 @@
#include <vector>
#include <boost/filesystem.hpp>
#include <sqlite3.h>
#include <osquery/database/results.h>
#ifndef STR
@ -43,62 +40,6 @@ enum osqueryTool {
OSQUERY_TOOL_TEST,
};
/**
* @brief Execute a query
*
* This is a lower-level version of osquery::SQL. Prefer to use osquery::SQL.
*
* @code{.cpp}
* std::string q = "SELECT * FROM time;";
* int i = 0;
* auto qd = query(q, i);
* if (i == 0) {
* for (const auto& each : qd) {
* for (const auto& it : each) {
* LOG(INFO) << it.first << ": " << it.second;
* }
* }
* } else {
* LOG(ERROR) << "Error: " << i;
* }
* @endcode
*
* @param q the query to execute
* @param error_return an int indicating the success or failure of the query
*
* @return the results of the query
*/
osquery::QueryData query(const std::string& q, int& error_return);
/**
* @brief Execute a query on a specific database
*
* If you need to use a different database, other than the osquery default,
* use this method and pass along a pointer to a SQLite3 database. This is
* useful for testing.
*
* @param q the query to execute
* @param error_return an int indicating the success or failure of the query
* @param db the SQLite3 database to execute query q against
*
* @return the results of the query
*/
osquery::QueryData query(const std::string& q, int& error_return, sqlite3* db);
/**
* @brief Return a fully configured sqlite3 database object
*
* An osquery database is basically just a SQLite3 database with several
* virtual tables attached. This method is the main abstraction for creating
* SQLite3 databases within osquery.
*
* Note: osquery::initOsquery must be called before calling createDB in order
* for virtual tables to be registered.
*
* @return a SQLite3 database with all virtual tables attached
*/
sqlite3* createDB();
/**
* @brief Sets up various aspects of osquery execution state.
*

View File

@ -14,13 +14,16 @@
#include <memory>
#include <string>
#include <gtest/gtest_prod.h>
#include <osquery/database/db_handle.h>
#include <osquery/database/results.h>
#include <osquery/scheduler.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 {
/// Error message used when a query name isn't found in the database

View File

@ -21,16 +21,55 @@
namespace osquery {
/**
* @brief A boilerplate code helper to create a registry given a name and
* plugin base class type.
*
* Registries are types of plugins, e.g., config, logger, table. They are
* defined with a string name and Plugin derived class. There is an expectation
* that any 'item' registered will inherit from the registry plugin-derived
* type. But there is NO type enforcement on that intermediate class.
*
* This boilerplate macro puts the registry into a 'registry' namespace for
* organization and createa a global const int that may be instanciated
* in a header or implementation code without symbol duplication.
* The initialization is also boilerplate, whereas the Registry::create method
* (a whole-process-lived single instance object) creates and manages the
* registry instance.
*
* @param type A typename that derives from Plugin.
* @param name A string identifier for the registry.
*/
#define CREATE_REGISTRY(type, name) \
namespace registry { \
const auto type##Registry = Registry::create<type>(name); \
}
/**
* @brief A boilerplate code helper to create a registry given a name and
* plugin base class type. This 'lazy' registry does not automatically run
* Plugin::setUp on all items.
*
* @param type A typename that derives from Plugin.
* @param name A string identifier for the registry.
*/
#define CREATE_LAZY_REGISTRY(type, name) \
namespace registry { \
const auto type##Registry = Registry::create<type>(name, false); \
}
/**
* @brief A boilerplate code helper to register a plugin.
*
* Like CREATE_REGISTRY, REGISTER creates a boilerplate global instance to
* create an instance of the plugin type within the whole-process-lived registry
* single instance. Registry items must derive from the `RegistryType` defined
* by the CREATE_REGISTRY and Registry::create call.
*
* @param type A typename that derives from the RegistryType.
* @param registry The string name for the registry.
* @param name A string identifier for this registry item.
*/
#define REGISTER(type, registry, name) \
const auto type##RegistryItem = Registry::add<type>(registry, name);
@ -80,6 +119,11 @@ class RegistryCore {
* @brief Add a plugin to this registry by allocating and indexing
* a type Item and a key identifier.
*
* @code{.cpp}
* /// Instead of calling RegistryFactory::add use:
* REGISTER(Type, "registry_name", "item_name");
* @endcode
*
* @param item_name An identifier for this registry plugin.
* @return A success/failure status.
*/
@ -90,12 +134,11 @@ class RegistryCore {
}
// Run the item's constructor, the setUp call will happen later.
auto item = new Item();
auto item = (RegistryType*)new Item();
item->setName(item_name);
// Cast the specific registry-type derived item as the API typ the registry
// used when it was created using the registry factory.
auto base_item = reinterpret_cast<RegistryType*>(item);
std::shared_ptr<RegistryType> shared_item(base_item);
std::shared_ptr<RegistryType> shared_item(item);
items_[item_name] = shared_item;
return Status(0, "OK");
}
@ -160,6 +203,17 @@ class RegistryCore {
const std::map<std::string, RegistryTypeRef>& all() { return items_; }
/**
* @brief Allow a plugin to perform some setup functions when osquery starts.
*
* Doing work in a plugin constructor has unknown behavior. Plugins may
* be constructed at anytime during osquery's life, including global variable
* instanciation. To have a reliable state (aka, flags have been parsed,
* and logs are ready to stream), do construction work in Plugin::setUp.
*
* The registry `setUp` will iterate over all of its registry items and call
* their setup unless the registry is lazy (see CREATE_REGISTRY).
*/
void setUp() {
// If this registry does not auto-setup do NOT setup the registry items.
if (!auto_setup_) {
@ -216,8 +270,8 @@ class RegistryCore {
template <class TypeAPI>
class RegistryFactory : private boost::noncopyable {
protected:
typedef RegistryCore<TypeAPI> RegistryTypeAPI;
typedef std::shared_ptr<TypeAPI> TypeAPIRef;
typedef RegistryCore<TypeAPI> RegistryTypeAPI;
typedef std::shared_ptr<RegistryCore<TypeAPI> > RegistryTypeAPIRef;
public:
@ -249,8 +303,7 @@ class RegistryFactory : private boost::noncopyable {
return 0;
}
auto registry =
reinterpret_cast<RegistryTypeAPI*>(new RegistryCore<Type>(auto_setup));
auto registry = (RegistryTypeAPI*)new RegistryCore<Type>(auto_setup);
registry->setName(registry_name);
std::shared_ptr<RegistryTypeAPI> shared_registry(registry);
instance().registries_[registry_name] = shared_registry;

View File

@ -18,19 +18,6 @@
#include <osquery/tables.h>
namespace osquery {
/**
* @brief A map of SQLite status codes to their corresponding message string
*
* Details of this map are defined at: http://www.sqlite.org/c3ref/c_abort.html
*/
extern const std::map<int, std::string> kSQLiteReturnCodes;
/**
* @brief Get a string representation of a SQLite return code
*/
std::string getStringForSQLiteReturnCode(int code);
/**
* @brief The core interface to executing osquery SQL commands
*
@ -124,4 +111,45 @@ class SQL {
/// the internal member which holds the status of the query
Status status_;
};
/**
* @brief Execute a query
*
* This is a lower-level version of osquery::SQL. Prefer to use osquery::SQL.
*
* @code{.cpp}
* std::string q = "SELECT * FROM time;";
* QueryData results;
* auto status = query(q, results);
* if (status.ok()) {
* for (const auto& each : results) {
* for (const auto& it : each) {
* LOG(INFO) << it.first << ": " << it.second;
* }
* }
* } else {
* LOG(ERROR) << "Error: " << status.what();
* }
* @endcode
*
* @param q the query to execute
* @param results A QueryData structure to emit result rows on success.
* @return A status indicating query success.
*/
Status query(const std::string& query, QueryData& results);
/**
* @brief Analyze a query, providing information about the result columns
*
* This function asks SQLite to determine what the names and types are of the
* result columns of the provided query. Only table columns (not expressions or
* subqueries) can have their types determined. Types that are not determined
* are indicated with the string "UNKNOWN".
*
* @param q the query to analyze
* @param columns the vector to fill with column information
*
* @return status indicating success or failure of the operation
*/
Status getQueryColumns(const std::string& q, tables::TableColumns& columns);
}

View File

@ -17,8 +17,6 @@
#include <boost/lexical_cast.hpp>
#include <boost/property_tree/ptree.hpp>
#include <sqlite3.h>
#include <osquery/registry.h>
#include <osquery/core.h>
#include <osquery/database/results.h>
@ -300,39 +298,5 @@ class TablePlugin : public Plugin {
};
CREATE_REGISTRY(TablePlugin, "table");
/**
* @brief Analyze a query, providing information about the result columns
*
* This function asks SQLite to determine what the names and types are of the
* result columns of the provided query. Only table columns (not expressions or
* subqueries) can have their types determined. Types that are not determined
* are indicated with the string "UNKNOWN".
*
* @param q the query to analyze
* @param columns the vector to fill with column information
*
* @return status indicating success or failure of the operation
*/
Status getQueryColumns(const std::string& q, TableColumns& columns);
/**
* @brief Analyze a query, providing information about the result columns
*
* This function asks SQLite to determine what the names and types are of the
* result columns of the provided query. Only table columns (not expressions or
* subqueries) can have their types determined. Types that are not determined
* are indicated with the string "UNKNOWN".
*
* @param q the query to analyze
* @param columns the vector to fill with column information
* @param db the SQLite3 database to perform the analysis on
*
* @return status indicating success or failure of the operation
*/
Status getQueryColumns(const std::string& q,
TableColumns& columns,
sqlite3* db);
}
}

View File

@ -28,41 +28,18 @@ set(OSQUERY_LIBS
# The platform-specific core libraries.
if(APPLE)
ADD_OSQUERY_CORE_LINK("-mmacosx-version-min=${APPLE_MIN_ABI}")
ADD_OSQUERY_CORE_LINK("boost_thread-mt")
ADD_OSQUERY_CORE_LINK("lz4")
ADD_OSQUERY_LINK(TRUE "-mmacosx-version-min=${APPLE_MIN_ABI}")
ADD_OSQUERY_LINK(TRUE "boost_thread-mt")
ADD_OSQUERY_LINK(TRUE "lz4")
else()
ADD_OSQUERY_CORE_LINK("boost_thread")
ADD_OSQUERY_CORE_LINK("rt")
ADD_OSQUERY_LINK(TRUE "boost_thread")
ADD_OSQUERY_LINK(TRUE "rt")
endif()
# The remaining boost libraries are discovered with find_library.
ADD_OSQUERY_CORE_LINK("boost_system")
ADD_OSQUERY_CORE_LINK("boost_filesystem")
ADD_OSQUERY_CORE_LINK("boost_regex")
# Generate version from git
execute_process(
COMMAND git describe --tags HEAD --always
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE OSQUERY_BUILD_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions("
-DOSQUERY_BUILD_VERSION=${OSQUERY_BUILD_VERSION}
-D${OSQUERY_BUILD_OS}
-D${OSQUERY_BUILD_OS}_${OSQUERY_BUILD_DISTRO}
")
# Make sure deps were built before compiling
execute_process(
COMMAND "${CMAKE_SOURCE_DIR}/tools/provision.sh" check "${CMAKE_BINARY_DIR}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE OSQUERY_DEPS_MESSAGE
RESULT_VARIABLE OSQUERY_DEPS_CHECK
OUTPUT_STRIP_TRAILING_WHITESPACE
)
ADD_OSQUERY_LINK(TRUE "boost_system")
ADD_OSQUERY_LINK(TRUE "boost_filesystem")
ADD_OSQUERY_LINK(TRUE "boost_regex")
# Construct a set of all object files, starting with third-party and all
# of the osquery core objects (sources from ADD_CORE_LIBRARY macros).
@ -75,11 +52,11 @@ add_subdirectory(database)
add_subdirectory(devtools)
add_subdirectory(dispatcher)
add_subdirectory(events)
add_subdirectory(examples)
add_subdirectory(filesystem)
add_subdirectory(logger)
add_subdirectory(registry)
add_subdirectory(scheduler)
add_subdirectory(sql)
add_subdirectory(tables)
# Utility tables are table specs that are ALWAYS built into osquery core.
@ -89,123 +66,75 @@ GENERATE_UTILITY("time")
GENERATE_UTILITY("file")
GENERATE_UTILITY("hash")
# Finally amalgamate all the tables.
# Finally amalgamate the tables needed to compile.
AMALGAMATE("${CMAKE_SOURCE_DIR}" "utils" AMALGAMATION_UTILS)
ADD_OSQUERY_CORE_LIBRARY(osquery_utils_amalgamation ${AMALGAMATION_UTILS})
ADD_OSQUERY_LIBRARY(TRUE osquery_utils_amalgamation ${AMALGAMATION_UTILS})
list(APPEND OSQUERY_OBJECTS ${OSQUERY_SOURCES})
list(APPEND OSQUERY_LIBS ${OSQUERY_LINKS})
# Create the static libosquery (target called libosquery_basic).
# Create the static libosquery (everything but non-util tables).
set(CMAKE_MACOSX_RPATH 0)
add_library(libosquery_basic STATIC main/lib.cpp ${OSQUERY_OBJECTS})
target_link_libraries(libosquery_basic ${OSQUERY_LIBS})
set_target_properties(libosquery_basic PROPERTIES OUTPUT_NAME osquery)
install(TARGETS libosquery_basic ARCHIVE DESTINATION lib COMPONENT devel OPTIONAL)
add_library(libosquery STATIC main/lib.cpp ${OSQUERY_OBJECTS})
target_link_libraries(libosquery ${OSQUERY_LIBS})
set_target_properties(libosquery PROPERTIES OUTPUT_NAME osquery)
# Generate the osquery core tables (the non-util).
GENERATE_TABLES("${CMAKE_SOURCE_DIR}/osquery/tables" "${CMAKE_SOURCE_DIR}")
AMALGAMATE("${CMAKE_SOURCE_DIR}" "additional" AMALGAMATION)
ADD_OSQUERY_LIBRARY(osquery_amalgamation ${AMALGAMATION})
# Create the static libosquery_additional.
add_library(libosquery_additional STATIC ${OSQUERY_ADDITIONAL_SOURCES})
target_link_libraries(libosquery_additional ${OSQUERY_ADDITIONAL_LINKS})
set_target_properties(libosquery_additional PROPERTIES OUTPUT_NAME osquery_additional)
# Include the public API includes if make devel.
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" DESTINATION include COMPONENT devel OPTIONAL)
add_executable(shell main/shell.cpp)
TARGET_OSQUERY_LINK_WHOLE(shell libosquery_basic)
TARGET_OSQUERY_LINK_WHOLE(shell libosquery_additional)
set_target_properties(shell PROPERTIES OUTPUT_NAME osqueryi)
set_target_properties(shell PROPERTIES COMPILE_FLAGS ${OS_COMPILE_FLAGS})
install(TARGETS shell RUNTIME DESTINATION bin COMPONENT main)
add_executable(daemon main/daemon.cpp core/watcher.cpp)
TARGET_OSQUERY_LINK_WHOLE(daemon libosquery_basic)
TARGET_OSQUERY_LINK_WHOLE(daemon libosquery_additional)
set_target_properties(daemon PROPERTIES OUTPUT_NAME osqueryd)
set_target_properties(daemon PROPERTIES COMPILE_FLAGS ${OS_COMPILE_FLAGS})
install(TARGETS daemon RUNTIME DESTINATION bin COMPONENT main)
add_executable(run main/run.cpp)
TARGET_OSQUERY_LINK_WHOLE(run libosquery_basic)
TARGET_OSQUERY_LINK_WHOLE(run libosquery_additional)
set_target_properties(run PROPERTIES COMPILE_FLAGS ${OS_COMPILE_FLAGS})
# make devel
# make devel (implies install)
add_custom_target(devel
COMMAND ${CMAKE_COMMAND}
-D COMPONENT=devel
-P cmake_install.cmake
DEPENDS libosquery_basic
)
add_dependencies(devel libosquery_basic)
add_dependencies(devel libosquery)
# make install config files
install(FILES "${CMAKE_SOURCE_DIR}/tools/deployment/osquery.example.conf"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/osquery/" COMPONENT main)
if(APPLE)
install(FILES "${CMAKE_SOURCE_DIR}/tools/deployment/com.facebook.osqueryd.plist"
# Generate the osquery additional tables (the non-util).
GENERATE_TABLES("${CMAKE_SOURCE_DIR}/osquery/tables" "${CMAKE_SOURCE_DIR}")
AMALGAMATE("${CMAKE_SOURCE_DIR}" "additional" AMALGAMATION)
ADD_OSQUERY_LIBRARY(FALSE osquery_amalgamation ${AMALGAMATION})
if(NOT OSQUERY_BUILD_SDK_ONLY)
# Create the static libosquery_additional.
add_library(libosquery_additional STATIC ${OSQUERY_ADDITIONAL_SOURCES})
target_link_libraries(libosquery_additional ${OSQUERY_ADDITIONAL_LINKS})
set_target_properties(libosquery_additional PROPERTIES OUTPUT_NAME osquery_additional)
add_executable(shell main/shell.cpp)
TARGET_OSQUERY_LINK_WHOLE(shell libosquery)
TARGET_OSQUERY_LINK_WHOLE(shell libosquery_additional)
set_target_properties(shell PROPERTIES OUTPUT_NAME osqueryi)
add_executable(daemon main/daemon.cpp core/watcher.cpp)
TARGET_OSQUERY_LINK_WHOLE(daemon libosquery)
TARGET_OSQUERY_LINK_WHOLE(daemon libosquery_additional)
set_target_properties(daemon PROPERTIES OUTPUT_NAME osqueryd)
add_executable(run main/run.cpp)
TARGET_OSQUERY_LINK_WHOLE(run libosquery)
TARGET_OSQUERY_LINK_WHOLE(run libosquery_additional)
# Include the public API includes if make devel.
install(TARGETS libosquery ARCHIVE DESTINATION lib COMPONENT devel OPTIONAL)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" DESTINATION include COMPONENT devel OPTIONAL)
# make install (executables)
install(TARGETS shell RUNTIME DESTINATION bin COMPONENT main)
install(TARGETS daemon RUNTIME DESTINATION bin COMPONENT main)
# make install (config files)
install(FILES "${CMAKE_SOURCE_DIR}/tools/deployment/osquery.example.conf"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/osquery/" COMPONENT main)
else()
install(PROGRAMS "${CMAKE_SOURCE_DIR}/tools/deployment/osqueryd.initd"
DESTINATION "/etc/init.d/" RENAME "osqueryd" COMPONENT main)
endif()
# make package
if(APPLE)
add_custom_target(
packages
./tools/deployment/make_osx_package.sh
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Building default OS X package (no custom config)" VERBATIM
)
elseif(LINUX)
if(UBUNTU)
set(PACKAGE_TYPE "deb")
set(PACKAGE_DEPENDENCIES
"libc6 (>=2.15)"
"zlib1g"
"libbz2-1.0"
"libapt-pkg4.12"
"libreadline6"
)
if(OSQUERY_BUILD_DISTRO STREQUAL "PRECISE")
set(PACKAGE_DEPENDENCIES
"${PACKAGE_DEPENDENCIES}"
"libstdc++6"
"libudev0"
)
elseif(OSQUERY_BUILD_DISTRO STREQUAL "TRUSTY")
set(PACKAGE_DEPENDENCIES
"${PACKAGE_DEPENDENCIES}"
"libstdc++6 (>= 4.8)"
"libudev1"
)
endif()
elseif(CENTOS)
set(PACKAGE_TYPE "rpm")
set(PACKAGE_DEPENDENCIES
"glibc >= 2.12"
"openssl >= 1.0"
"readline"
"zlib"
"snappy"
"bzip2-libs"
"procps"
"libudev"
"rpm-libs"
)
if(APPLE)
install(FILES "${CMAKE_SOURCE_DIR}/tools/deployment/com.facebook.osqueryd.plist"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/osquery/" COMPONENT main)
else()
install(PROGRAMS "${CMAKE_SOURCE_DIR}/tools/deployment/osqueryd.initd"
DESTINATION "/etc/init.d/" RENAME "osqueryd" COMPONENT main)
endif()
JOIN("${PACKAGE_DEPENDENCIES}" ", " PACKAGE_DEPENDENCIES)
add_custom_target(
packages
./tools/deployment/make_linux_package.sh -t ${PACKAGE_TYPE} -d "${PACKAGE_DEPENDENCIES}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Building linux packages (no custom config)" VERBATIM
)
else()
# Build the example extension with the SDK
add_executable(example_extension examples/example_extension.cpp)
TARGET_OSQUERY_LINK_WHOLE(example_extension libosquery)
set_target_properties(example_extension PROPERTIES OUTPUT_NAME example_extension)
endif()

View File

@ -1,6 +1,9 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_config
ADD_OSQUERY_LIBRARY(TRUE osquery_config
config.cpp
)
ADD_OSQUERY_LIBRARY(FALSE osquery_config_plugins
plugins/filesystem.cpp
)
ADD_OSQUERY_TEST(config_tests config_tests.cpp)
ADD_OSQUERY_TEST(FALSE config_tests config_tests.cpp)

View File

@ -14,6 +14,7 @@
#include <osquery/core.h>
#include <osquery/flags.h>
#include <osquery/registry.h>
#include <osquery/sql.h>
#include "osquery/core/test_util.h"
@ -61,9 +62,9 @@ TEST_F(ConfigTests, test_queries_execute) {
EXPECT_EQ(queries.size(), 1);
for (const auto& i : queries) {
int err;
auto r = query(i.query, err);
EXPECT_EQ(err, 0);
QueryData results;
auto status = query(i.query, results);
EXPECT_TRUE(status.ok());
}
}
}

View File

@ -6,27 +6,24 @@ else()
set (OS_CORE_SOURCE "")
endif()
ADD_OSQUERY_CORE_LIBRARY(osquery_core
ADD_OSQUERY_LIBRARY(TRUE osquery_core
conversions.cpp
init.cpp
sql.cpp
sqlite_util.cpp
system.cpp
test_util.cpp
${OS_CORE_SOURCE}
tables.cpp
virtual_table.cpp
text.cpp
flags.cpp
hash.cpp
)
ADD_OSQUERY_TEST(hash_test hash_tests.cpp)
ADD_OSQUERY_TEST(status_test status_tests.cpp)
ADD_OSQUERY_TEST(sql_test sql_tests.cpp)
ADD_OSQUERY_TEST(sqlite_util_tests sqlite_util_tests.cpp)
ADD_OSQUERY_TEST(tables_tests tables_tests.cpp)
ADD_OSQUERY_TEST(virtual_table_tests virtual_table_tests.cpp)
ADD_OSQUERY_TEST(test_util_tests test_util_tests.cpp)
ADD_OSQUERY_TEST(text_tests text_tests.cpp)
ADD_OSQUERY_TEST(conversions_tests conversions_tests.cpp)
ADD_OSQUERY_LIBRARY(TRUE osquery_test_util
test_util.cpp
)
ADD_OSQUERY_TEST(TRUE hash_test hash_tests.cpp)
ADD_OSQUERY_TEST(TRUE status_test status_tests.cpp)
ADD_OSQUERY_TEST(TRUE tables_tests tables_tests.cpp)
ADD_OSQUERY_TEST(TRUE test_util_tests test_util_tests.cpp)
ADD_OSQUERY_TEST(TRUE text_tests text_tests.cpp)
ADD_OSQUERY_TEST(TRUE conversions_tests conversions_tests.cpp)

View File

@ -1,117 +0,0 @@
/*
* 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 <osquery/core.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/tables.h>
#include <osquery/registry.h>
#include "osquery/core/virtual_table.h"
namespace osquery {
const std::map<int, std::string> kSQLiteReturnCodes = {
{0, "SQLITE_OK: Successful result"},
{1, "SQLITE_ERROR: SQL error or missing database"},
{2, "SQLITE_INTERNAL: Internal logic error in SQLite"},
{3, "SQLITE_PERM: Access permission denied"},
{4, "SQLITE_ABORT: Callback routine requested an abort"},
{5, "SQLITE_BUSY: The database file is locked"},
{6, "SQLITE_LOCKED: A table in the database is locked"},
{7, "SQLITE_NOMEM: A malloc() failed"},
{8, "SQLITE_READONLY: Attempt to write a readonly database"},
{9, "SQLITE_INTERRUPT: Operation terminated by sqlite3_interrupt()"},
{10, "SQLITE_IOERR: Some kind of disk I/O error occurred"},
{11, "SQLITE_CORRUPT: The database disk image is malformed"},
{12, "SQLITE_NOTFOUND: Unknown opcode in sqlite3_file_control()"},
{13, "SQLITE_FULL: Insertion failed because database is full"},
{14, "SQLITE_CANTOPEN: Unable to open the database file"},
{15, "SQLITE_PROTOCOL: Database lock protocol error"},
{16, "SQLITE_EMPTY: Database is empty"},
{17, "SQLITE_SCHEMA: The database schema changed"},
{18, "SQLITE_TOOBIG: String or BLOB exceeds size limit"},
{19, "SQLITE_CONSTRAINT: Abort due to constraint violation"},
{20, "SQLITE_MISMATCH: Data type mismatch"},
{21, "SQLITE_MISUSE: Library used incorrectly"},
{22, "SQLITE_NOLFS: Uses OS features not supported on host"},
{23, "SQLITE_AUTH: Authorization denied"},
{24, "SQLITE_FORMAT: Auxiliary database format error"},
{25, "SQLITE_RANGE: 2nd parameter to sqlite3_bind out of range"},
{26, "SQLITE_NOTADB: File opened that is not a database file"},
{27, "SQLITE_NOTICE: Notifications from sqlite3_log()"},
{28, "SQLITE_WARNING: Warnings from sqlite3_log()"},
{100, "SQLITE_ROW: sqlite3_step() has another row ready"},
{101, "SQLITE_DONE: sqlite3_step() has finished executing"},
};
const std::map<tables::ConstraintOperator, std::string> kSQLOperatorRepr = {
{tables::EQUALS, "="},
{tables::GREATER_THAN, ">"},
{tables::LESS_THAN_OR_EQUALS, "<="},
{tables::LESS_THAN, "<"},
{tables::GREATER_THAN_OR_EQUALS, ">="}, };
std::string getStringForSQLiteReturnCode(int code) {
if (kSQLiteReturnCodes.find(code) != kSQLiteReturnCodes.end()) {
return kSQLiteReturnCodes.at(code);
} else {
std::ostringstream s;
s << "Error: " << code << " is not a valid SQLite result code";
return s.str();
}
}
SQL::SQL(const std::string& q) {
int code = 0;
results_ = query(q, code);
status_ = Status(code, getStringForSQLiteReturnCode(code));
}
QueryData SQL::rows() { return results_; }
bool SQL::ok() { return status_.ok(); }
std::string SQL::getMessageString() { return status_.toString(); }
std::vector<std::string> SQL::getTableNames() {
std::vector<std::string> results;
// for (const auto& it : REGISTERED_TABLES) {
// results.push_back(it.first);
//}
for (const auto& name : Registry::names("table")) {
results.push_back(name);
}
return results;
}
QueryData SQL::selectAllFrom(const std::string& table) {
std::string query = "select * from `" + table + "`;";
return SQL(query).rows();
}
QueryData SQL::selectAllFrom(const std::string& table,
const std::string& column,
tables::ConstraintOperator op,
const std::string& expr) {
std::string query = "select * from `" + table + "` where `" + column + "`";
if (kSQLOperatorRepr.count(op) > 0) {
query += kSQLOperatorRepr.at(op);
} else {
LOG(WARNING) << "Cannot query using unknown SQL operator: " << op;
return {};
}
query += "'" + expr + "'";
return SQL(query).rows();
}
}

View File

@ -1,67 +0,0 @@
/*
* 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/sqlite_util.h"
#include "osquery/core/virtual_table.h"
namespace osquery {
sqlite3* createDB() {
sqlite3* db = nullptr;
sqlite3_open(":memory:", &db);
osquery::tables::attachVirtualTables(db);
return db;
}
QueryData query(const std::string& q, int& error_return) {
sqlite3* db = createDB();
QueryData results = query(q, error_return, db);
sqlite3_close(db);
return results;
}
QueryData query(const std::string& q, int& error_return, sqlite3* db) {
QueryData d;
char* err = nullptr;
sqlite3_exec(db, q.c_str(), query_data_callback, &d, &err);
if (err != nullptr) {
LOG(ERROR) << "Error launching query: " << err;
error_return = 1;
sqlite3_free(err);
} else {
error_return = 0;
}
return d;
}
int query_data_callback(void* argument,
int argc,
char* argv[],
char* column[]) {
if (argument == nullptr) {
LOG(ERROR) << "query_data_callback received nullptr as data argument";
return SQLITE_MISUSE;
}
QueryData* qData = (QueryData*)argument;
Row r;
for (int i = 0; i < argc; i++) {
r[column[i]] = argv[i];
}
(*qData).push_back(r);
return 0;
}
}

View File

@ -1,18 +0,0 @@
/*
* 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 {
// 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[]);
}

View File

@ -1,57 +0,0 @@
/*
* 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 {
class SQLiteUtilTests : public testing::Test {};
TEST_F(SQLiteUtilTests, test_simple_query_execution) {
int err;
auto db = createTestDB();
auto results = query(kTestQuery, err, db);
sqlite3_close(db);
EXPECT_EQ(err, 0);
EXPECT_EQ(results, getTestDBExpectedResults());
}
TEST_F(SQLiteUtilTests, test_passing_callback_no_data_param) {
char* err = nullptr;
auto db = createTestDB();
sqlite3_exec(db, kTestQuery.c_str(), query_data_callback, nullptr, &err);
sqlite3_close(db);
EXPECT_TRUE(err != nullptr);
if (err != nullptr) {
sqlite3_free(err);
}
}
TEST_F(SQLiteUtilTests, test_aggregate_query) {
int err;
auto db = createTestDB();
QueryData d = query(kTestQuery, err, db);
sqlite3_close(db);
EXPECT_EQ(err, 0);
}
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -200,55 +200,5 @@ std::string TablePlugin::statement() {
return "CREATE TABLE " + name_ + columnDefinition();
}
Status getQueryColumns(const std::string& q, tables::TableColumns& columns) {
sqlite3* db = createDB();
Status status = getQueryColumns(q, columns, db);
sqlite3_close(db);
return status;
}
Status getQueryColumns(const std::string& q,
tables::TableColumns& columns,
sqlite3* db) {
int rc;
// Will automatically handle calling sqlite3_finalize on the prepared stmt
// (Note that sqlite3_finalize is explicitly a nop for nullptr)
std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*> stmt_managed(
nullptr, sqlite3_finalize);
sqlite3_stmt* stmt = stmt_managed.get();
// Turn the query into a prepared statement
rc = sqlite3_prepare_v2(db, q.c_str(), q.length() + 1, &stmt, nullptr);
if (rc != SQLITE_OK) {
return Status(1, sqlite3_errmsg(db));
}
// Get column count
int num_columns = sqlite3_column_count(stmt);
std::vector<std::pair<std::string, std::string> > results;
results.reserve(num_columns);
// Get column names and types
for (int i = 0; i < num_columns; ++i) {
const char* col_name = sqlite3_column_name(stmt, i);
const char* col_type = sqlite3_column_decltype(stmt, i);
if (col_name == nullptr) {
return Status(1, "Got nullptr for column name");
}
if (col_type == nullptr) {
// Types are only returned for table columns (not expressions or
// subqueries). See docs for column_decltype
// (https://www.sqlite.org/c3ref/column_decltype.html).
col_type = "UNKNOWN";
}
results.push_back({col_name, col_type});
}
columns = std::move(results);
return Status(0, "OK");
}
}
}

View File

@ -110,50 +110,6 @@ TEST_F(TablesTests, test_constraint_map) {
EXPECT_TRUE(cm["path"].matches("some"));
}
TEST_F(TablesTests, test_get_query_columns) {
std::unique_ptr<sqlite3, decltype(sqlite3_close)*> db_managed(createDB(),
sqlite3_close);
sqlite3* db = db_managed.get();
std::string query;
Status status;
TableColumns results;
query =
"SELECT hour, minutes, seconds, version, config_md5, config_path, \
pid FROM time JOIN osquery_info";
status = getQueryColumns(query, results, db);
ASSERT_TRUE(status.ok());
ASSERT_EQ(7, results.size());
EXPECT_EQ(std::make_pair(std::string("hour"), std::string("INTEGER")),
results[0]);
EXPECT_EQ(std::make_pair(std::string("minutes"), std::string("INTEGER")),
results[1]);
EXPECT_EQ(std::make_pair(std::string("seconds"), std::string("INTEGER")),
results[2]);
EXPECT_EQ(std::make_pair(std::string("version"), std::string("TEXT")),
results[3]);
EXPECT_EQ(std::make_pair(std::string("config_md5"), std::string("TEXT")),
results[4]);
EXPECT_EQ(std::make_pair(std::string("config_path"), std::string("TEXT")),
results[5]);
EXPECT_EQ(std::make_pair(std::string("pid"), std::string("INTEGER")),
results[6]);
query = "SELECT hour + 1 AS hour1, minutes + 1 FROM time";
status = getQueryColumns(query, results, db);
ASSERT_TRUE(status.ok());
ASSERT_EQ(2, results.size());
EXPECT_EQ(std::make_pair(std::string("hour1"), std::string("UNKNOWN")),
results[0]);
EXPECT_EQ(std::make_pair(std::string("minutes + 1"), std::string("UNKNOWN")),
results[1]);
query = "SELECT * FROM foo";
status = getQueryColumns(query, results, db);
ASSERT_FALSE(status.ok());
}
}
}

View File

@ -16,7 +16,6 @@
#include <osquery/filesystem.h>
#include <osquery/logger.h>
#include "osquery/core/sqlite_util.h"
#include "osquery/core/test_util.h"
namespace pt = boost::property_tree;
@ -26,27 +25,6 @@ namespace osquery {
const std::string kTestQuery = "SELECT * FROM test_table";
const std::string kTestDataPath = "../../../../tools/tests/";
sqlite3* createTestDB() {
sqlite3* db = createDB();
char* err = nullptr;
std::vector<std::string> queries = {
"CREATE TABLE test_table ("
"username varchar(30) primary key, "
"age int"
")",
"INSERT INTO test_table VALUES (\"mike\", 23)",
"INSERT INTO test_table VALUES (\"matt\", 24)"};
for (auto q : queries) {
sqlite3_exec(db, q.c_str(), nullptr, nullptr, &err);
if (err != nullptr) {
LOG(ERROR) << "Error creating test database: " << err;
return nullptr;
}
}
return db;
}
QueryData getTestDBExpectedResults() {
QueryData d;
Row row1;

View File

@ -31,10 +31,6 @@ namespace osquery {
extern const std::string kTestQuery;
extern const std::string kTestDataPath;
// createTestDB instantiates a sqlite3 struct and populates it with some test
// data
sqlite3* createTestDB();
// getTestDBExpectedResults returns the results of kTestQuery of the table that
// initially gets returned from createTestDB()
osquery::QueryData getTestDBExpectedResults();

View File

@ -21,32 +21,6 @@ namespace osquery {
class TestUtilTests : public testing::Test {};
TEST_F(TestUtilTests, test_expected_results) {
int err;
auto db = createTestDB();
auto results = query(kTestQuery, err, db);
sqlite3_close(db);
EXPECT_EQ(err, 0);
EXPECT_EQ(results, getTestDBExpectedResults());
}
TEST_F(TestUtilTests, test_get_test_db_result_stream) {
auto db = createTestDB();
auto results = getTestDBResultStream();
for (auto r : results) {
char* err_char = nullptr;
sqlite3_exec(db, (r.first).c_str(), nullptr, nullptr, &err_char);
EXPECT_TRUE(err_char == nullptr);
if (err_char != nullptr) {
sqlite3_free(err_char);
ASSERT_TRUE(false);
}
int err_int;
auto expected = query(kTestQuery, err_int, db);
EXPECT_EQ(expected, r.second);
}
sqlite3_close(db);
}
}
int main(int argc, char* argv[]) {

View File

@ -1,9 +1,9 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_database
ADD_OSQUERY_LIBRARY(TRUE osquery_database
db_handle.cpp
query.cpp
results.cpp
)
ADD_OSQUERY_TEST(query_tests query_tests.cpp)
ADD_OSQUERY_TEST(db_handle_tests db_handle_tests.cpp)
ADD_OSQUERY_TEST(results_tests results_tests.cpp)
ADD_OSQUERY_TEST(TRUE query_tests query_tests.cpp)
ADD_OSQUERY_TEST(TRUE db_handle_tests db_handle_tests.cpp)
ADD_OSQUERY_TEST(TRUE results_tests results_tests.cpp)

View File

@ -1,6 +1,6 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_devtools
ADD_OSQUERY_LIBRARY(FALSE osquery_devtools
shell.cpp
printer.cpp
)
ADD_OSQUERY_TEST(printer_tests printer_tests.cpp)
ADD_OSQUERY_TEST(FALSE printer_tests printer_tests.cpp)

View File

@ -84,7 +84,7 @@
#include <osquery/devtools.h>
#include <osquery/flags.h>
#include "osquery/core/virtual_table.h"
#include "osquery/sql/virtual_table.h"
// Json is a specific form of pretty printing.
namespace osquery {

View File

@ -1,7 +1,7 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_dispatcher
ADD_OSQUERY_LIBRARY(TRUE osquery_dispatcher
dispatcher.cpp
)
if(APPLE)
ADD_OSQUERY_TEST(dispatcher_tests dispatcher_tests.cpp)
ADD_OSQUERY_TEST(TRUE dispatcher_tests dispatcher_tests.cpp)
endif()

View File

@ -1,36 +1,36 @@
SET(OSQUERY_EVENTS_SOURCES "")
if(APPLE)
ADD_OSQUERY_CORE_LINK("-framework CoreServices")
ADD_OSQUERY_CORE_LINK("-framework SystemConfiguration")
ADD_OSQUERY_CORE_LINK("-framework IOKit")
ADD_OSQUERY_LINK(FALSE "-framework CoreServices")
ADD_OSQUERY_LINK(FALSE "-framework SystemConfiguration")
ADD_OSQUERY_LINK(FALSE "-framework IOKit")
ADD_OSQUERY_CORE_LIBRARY(osquery_events_darwin
ADD_OSQUERY_LIBRARY(FALSE osquery_events_darwin
darwin/fsevents.cpp
darwin/iokit_hid.cpp
darwin/scnetwork.cpp
)
elseif(FREEBSD)
ADD_OSQUERY_CORE_LIBRARY(osquery_events_freebsd
ADD_OSQUERY_LIBRARY(FALSE osquery_events_freebsd
)
else()
ADD_OSQUERY_CORE_LINK("udev")
ADD_OSQUERY_LINK(FALSE "udev")
ADD_OSQUERY_CORE_LIBRARY(osquery_events_linux
ADD_OSQUERY_LIBRARY(FALSE osquery_events_linux
linux/inotify.cpp
linux/udev.cpp
)
endif()
ADD_OSQUERY_CORE_LIBRARY(osquery_events
ADD_OSQUERY_LIBRARY(TRUE osquery_events
events.cpp
)
ADD_OSQUERY_TEST(events_tests events_tests.cpp)
ADD_OSQUERY_TEST(events_database_tests events_database_tests.cpp)
ADD_OSQUERY_TEST(TRUE events_tests events_tests.cpp)
ADD_OSQUERY_TEST(TRUE events_database_tests events_database_tests.cpp)
if(APPLE)
ADD_OSQUERY_TEST(fsevents_tests darwin/fsevents_tests.cpp)
ADD_OSQUERY_TEST(FALSE fsevents_tests darwin/fsevents_tests.cpp)
elseif(LINUX)
ADD_OSQUERY_TEST(inotify_tests linux/inotify_tests.cpp)
ADD_OSQUERY_TEST(FALSE inotify_tests linux/inotify_tests.cpp)
endif()

View File

@ -1 +0,0 @@
ADD_OSQUERY_TEST(example_test example_test.cpp)

View File

@ -0,0 +1,39 @@
/*
* 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 {
class ExampleTable : public tables::TablePlugin {
private:
tables::TableColumns columns() {
return {{"example_text", "TEXT"}, {"example_integer", "INTEGER"}};
}
QueryData generate(tables::QueryContext& request) {
QueryData results;
Row r;
r["example_text"] = "example";
r["example_integer"] = INTEGER(1);
results.push_back(r);
return results;
}
};
REGISTER(ExampleTable, "table", "example");
}
int main(int argc, char* argv[]) {
// Do some broadcast of the registry.
auto example = std::make_shared<osquery::ExampleTable>();
}

View File

@ -1,22 +1,22 @@
if(APPLE)
ADD_OSQUERY_CORE_OBJCXX_LIBRARY(osquery_filesystem_objc
ADD_OSQUERY_OBJCXX_LIBRARY(TRUE osquery_filesystem_objc
darwin/plist.mm
)
ADD_OSQUERY_CORE_LINK("-framework Foundation")
ADD_OSQUERY_LINK(TRUE "-framework Foundation")
elseif(UBUNTU OR CENTOS)
ADD_OSQUERY_CORE_LIBRARY(osquery_filesystem_linux
ADD_OSQUERY_LIBRARY(TRUE osquery_filesystem_linux
linux/mem.cpp
linux/proc.cpp
)
endif()
ADD_OSQUERY_CORE_LIBRARY(osquery_filesystem
ADD_OSQUERY_LIBRARY(TRUE osquery_filesystem
filesystem.cpp
)
ADD_OSQUERY_TEST(filesystem_tests filesystem_tests.cpp)
ADD_OSQUERY_TEST(TRUE filesystem_tests filesystem_tests.cpp)
if(APPLE)
ADD_OSQUERY_TEST(plist_tests darwin/plist_tests.cpp)
ADD_OSQUERY_TEST(plist_benchmark darwin/plist_benchmark.cpp)
ADD_OSQUERY_TEST(TRUE plist_tests darwin/plist_tests.cpp)
ADD_OSQUERY_TEST(TRUE plist_benchmark darwin/plist_benchmark.cpp)
endif()

View File

@ -1,4 +1,10 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_logger logger.cpp plugins/filesystem.cpp)
ADD_OSQUERY_LIBRARY(TRUE osquery_logger
logger.cpp
)
add_dependencies(osquery_logger libglog)
ADD_OSQUERY_TEST(logger_tests logger_tests.cpp)
ADD_OSQUERY_LIBRARY(FALSE osquery_logger_plugins
plugins/filesystem.cpp
)
ADD_OSQUERY_TEST(FALSE logger_tests logger_tests.cpp)

View File

@ -15,6 +15,7 @@
#include <osquery/core.h>
#include <osquery/events.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
DEFINE_string(query, "", "query to execute");
DEFINE_int32(iterations, 1, "times to run the query in question");
@ -41,11 +42,12 @@ int main(int argc, char* argv[]) {
::sleep(FLAGS_delay);
}
osquery::QueryData results;
for (int i = 0; i < FLAGS_iterations; ++i) {
printf("Executing: %s\n", FLAGS_query.c_str());
osquery::query(FLAGS_query, result);
if (result != 0) {
fprintf(stderr, "Query failed: %d\n", result);
auto status = osquery::query(FLAGS_query, results);
if (!status.ok()) {
fprintf(stderr, "Query failed: %d\n", status.getCode());
break;
} else {
if (FLAGS_delay != 0) {

View File

@ -15,11 +15,13 @@
int main(int argc, char *argv[]) {
osquery::FLAGS_db_path = "/tmp/rocksdb-osquery-shell";
// Parse/apply flags, start registry, load logger/config plugins.
osquery::initOsquery(argc, argv, osquery::OSQUERY_TOOL_SHELL);
// Start event threads.
osquery::EventFactory::delay();
// Virtual tables will be attached to the shell's in-memory SQLite DB.
int retcode = osquery::launchIntoShell(argc, argv);
// Finally shutdown.

View File

@ -1,5 +1,5 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_registry
ADD_OSQUERY_LIBRARY(TRUE osquery_registry
registry.cpp
)
ADD_OSQUERY_TEST(core_registry_tests registry_tests.cpp)
ADD_OSQUERY_TEST(TRUE registry_tests registry_tests.cpp)

View File

@ -1,5 +1,5 @@
ADD_OSQUERY_CORE_LIBRARY(osquery_scheduler
ADD_OSQUERY_LIBRARY(TRUE osquery_scheduler
scheduler.cpp
)
ADD_OSQUERY_TEST(scheduler_tests scheduler_tests.cpp)
ADD_OSQUERY_TEST(TRUE scheduler_tests scheduler_tests.cpp)

View File

@ -0,0 +1,16 @@
ADD_OSQUERY_LIBRARY(TRUE osquery_sql
sql.cpp
)
if(NOT OSQUERY_BUILD_SDK_ONLY)
set(SQL_INTERNAL TRUE)
endif()
ADD_OSQUERY_LIBRARY(SQL_INTERNAL osquery_sql_internal
sqlite_util.cpp
virtual_table.cpp
)
ADD_OSQUERY_TEST(TRUE sql_test sql_tests.cpp)
ADD_OSQUERY_TEST(SQL_INTERNAL sqlite_util_tests sqlite_util_tests.cpp)
ADD_OSQUERY_TEST(SQL_INTERNAL virtual_table_tests virtual_table_tests.cpp)

89
osquery/sql/sql.cpp Normal file
View File

@ -0,0 +1,89 @@
/*
* 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 <osquery/core.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/tables.h>
#include <osquery/registry.h>
#ifndef OSQUERY_BUILD_SDK
#include "osquery/sql/sqlite_util.h"
#endif
namespace osquery {
const std::map<tables::ConstraintOperator, std::string> kSQLOperatorRepr = {
{tables::EQUALS, "="},
{tables::GREATER_THAN, ">"},
{tables::LESS_THAN_OR_EQUALS, "<="},
{tables::LESS_THAN, "<"},
{tables::GREATER_THAN_OR_EQUALS, ">="},
};
SQL::SQL(const std::string& q) { status_ = query(q, results_); }
QueryData SQL::rows() { return results_; }
bool SQL::ok() { return status_.ok(); }
std::string SQL::getMessageString() { return status_.toString(); }
std::vector<std::string> SQL::getTableNames() {
std::vector<std::string> results;
for (const auto& name : Registry::names("table")) {
results.push_back(name);
}
return results;
}
QueryData SQL::selectAllFrom(const std::string& table) {
std::string query = "select * from `" + table + "`;";
return SQL(query).rows();
}
QueryData SQL::selectAllFrom(const std::string& table,
const std::string& column,
tables::ConstraintOperator op,
const std::string& expr) {
std::string query = "select * from `" + table + "` where `" + column + "`";
if (kSQLOperatorRepr.count(op) > 0) {
query += kSQLOperatorRepr.at(op);
} else {
LOG(WARNING) << "Cannot query using unknown SQL operator: " << op;
return {};
}
query += "'" + expr + "'";
return SQL(query).rows();
}
Status query(const std::string& q, QueryData& results) {
// Depending on the build type (core or sdk/extension) osquery will call the
// internal SQL implementation or the Thrift API endpoint.
#ifndef OSQUERY_BUILD_SDK
return queryInternal(q, results);
#else
return Status(0, "OK");
#endif
}
Status getQueryColumns(const std::string& q, tables::TableColumns& columns) {
// Depending on the build type (core or sdk/extension) osquery will call the
// internal SQL implementation or the Thrift API endpoint.
#ifndef OSQUERY_BUILD_SDK
return getQueryColumnsInternal(q, columns);
#else
return Status(0, "OK");
#endif
}
}

View File

@ -3,7 +3,7 @@
* 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
* 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.
*
*/
@ -20,7 +20,6 @@ class SQLTests : public testing::Test {};
TEST_F(SQLTests, test_simple_query_execution) {
auto sql = SQL("SELECT * FROM time");
EXPECT_TRUE(sql.ok());
EXPECT_EQ(sql.getMessageString(), getStringForSQLiteReturnCode(0));
EXPECT_EQ(sql.rows().size(), 1);
}

155
osquery/sql/sqlite_util.cpp Normal file
View File

@ -0,0 +1,155 @@
/*
* 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/sql.h>
#include "osquery/sql/sqlite_util.h"
#include "osquery/sql/virtual_table.h"
namespace osquery {
const std::map<int, std::string> kSQLiteReturnCodes = {
{0, "SQLITE_OK: Successful result"},
{1, "SQLITE_ERROR: SQL error or missing database"},
{2, "SQLITE_INTERNAL: Internal logic error in SQLite"},
{3, "SQLITE_PERM: Access permission denied"},
{4, "SQLITE_ABORT: Callback routine requested an abort"},
{5, "SQLITE_BUSY: The database file is locked"},
{6, "SQLITE_LOCKED: A table in the database is locked"},
{7, "SQLITE_NOMEM: A malloc() failed"},
{8, "SQLITE_READONLY: Attempt to write a readonly database"},
{9, "SQLITE_INTERRUPT: Operation terminated by sqlite3_interrupt()"},
{10, "SQLITE_IOERR: Some kind of disk I/O error occurred"},
{11, "SQLITE_CORRUPT: The database disk image is malformed"},
{12, "SQLITE_NOTFOUND: Unknown opcode in sqlite3_file_control()"},
{13, "SQLITE_FULL: Insertion failed because database is full"},
{14, "SQLITE_CANTOPEN: Unable to open the database file"},
{15, "SQLITE_PROTOCOL: Database lock protocol error"},
{16, "SQLITE_EMPTY: Database is empty"},
{17, "SQLITE_SCHEMA: The database schema changed"},
{18, "SQLITE_TOOBIG: String or BLOB exceeds size limit"},
{19, "SQLITE_CONSTRAINT: Abort due to constraint violation"},
{20, "SQLITE_MISMATCH: Data type mismatch"},
{21, "SQLITE_MISUSE: Library used incorrectly"},
{22, "SQLITE_NOLFS: Uses OS features not supported on host"},
{23, "SQLITE_AUTH: Authorization denied"},
{24, "SQLITE_FORMAT: Auxiliary database format error"},
{25, "SQLITE_RANGE: 2nd parameter to sqlite3_bind out of range"},
{26, "SQLITE_NOTADB: File opened that is not a database file"},
{27, "SQLITE_NOTICE: Notifications from sqlite3_log()"},
{28, "SQLITE_WARNING: Warnings from sqlite3_log()"},
{100, "SQLITE_ROW: sqlite3_step() has another row ready"},
{101, "SQLITE_DONE: sqlite3_step() has finished executing"},
};
std::string getStringForSQLiteReturnCode(int code) {
if (kSQLiteReturnCodes.find(code) != kSQLiteReturnCodes.end()) {
return kSQLiteReturnCodes.at(code);
} else {
std::ostringstream s;
s << "Error: " << code << " is not a valid SQLite result code";
return s.str();
}
}
sqlite3* createDB() {
sqlite3* db = nullptr;
sqlite3_open(":memory:", &db);
tables::attachVirtualTables(db);
return db;
}
int queryDataCallback(void* argument, int argc, char* argv[], char* column[]) {
if (argument == nullptr) {
LOG(ERROR) << "queryDataCallback received nullptr as data argument";
return SQLITE_MISUSE;
}
QueryData* qData = (QueryData*)argument;
Row r;
for (int i = 0; i < argc; i++) {
r[column[i]] = argv[i];
}
(*qData).push_back(r);
return 0;
}
Status queryInternal(const std::string& q, QueryData& results) {
sqlite3* db = createDB();
auto status = queryInternal(q, results, db);
sqlite3_close(db);
return status;
}
Status queryInternal(const std::string& q, QueryData& results, sqlite3* db) {
char* err = nullptr;
sqlite3_exec(db, q.c_str(), queryDataCallback, &results, &err);
if (err != nullptr) {
sqlite3_free(err);
return Status(1, "Error running query: " + q);
}
return Status(0, "OK");
}
Status getQueryColumnsInternal(const std::string& q,
tables::TableColumns& columns) {
sqlite3* db = createDB();
Status status = getQueryColumnsInternal(q, columns, db);
sqlite3_close(db);
return status;
}
Status getQueryColumnsInternal(const std::string& q,
tables::TableColumns& columns,
sqlite3* db) {
int rc;
// Will automatically handle calling sqlite3_finalize on the prepared stmt
// (Note that sqlite3_finalize is explicitly a nop for nullptr)
std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*> stmt_managed(
nullptr, sqlite3_finalize);
sqlite3_stmt* stmt = stmt_managed.get();
// Turn the query into a prepared statement
rc = sqlite3_prepare_v2(db, q.c_str(), q.length() + 1, &stmt, nullptr);
if (rc != SQLITE_OK) {
return Status(1, sqlite3_errmsg(db));
}
// Get column count
int num_columns = sqlite3_column_count(stmt);
std::vector<std::pair<std::string, std::string> > results;
results.reserve(num_columns);
// Get column names and types
for (int i = 0; i < num_columns; ++i) {
const char* col_name = sqlite3_column_name(stmt, i);
const char* col_type = sqlite3_column_decltype(stmt, i);
if (col_name == nullptr) {
return Status(1, "Got nullptr for column name");
}
if (col_type == nullptr) {
// Types are only returned for table columns (not expressions or
// subqueries). See docs for column_decltype
// (https://www.sqlite.org/c3ref/column_decltype.html).
col_type = "UNKNOWN";
}
results.push_back({col_name, col_type});
}
columns = std::move(results);
return Status(0, "OK");
}
}

84
osquery/sql/sqlite_util.h Normal file
View File

@ -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.
*
*/
#pragma once
#include <sqlite3.h>
namespace osquery {
/**
* @brief A map of SQLite status codes to their corresponding message string
*
* Details of this map are defined at: http://www.sqlite.org/c3ref/c_abort.html
*/
extern const std::map<int, std::string> kSQLiteReturnCodes;
/// Internal (core) SQL implementation of the osquery query API.
Status queryInternal(const std::string& q, QueryData& results);
/**
* @brief Execute a query on a specific database
*
* If you need to use a different database, other than the osquery default,
* use this method and pass along a pointer to a SQLite3 database. This is
* useful for testing.
*
* @param q the query to execute
* @param results The QueryData struct to emit row on query success.
* @param db the SQLite3 database to execute query q against
*
* @return A status indicating SQL query results.
*/
Status queryInternal(const std::string& q, QueryData& results, sqlite3* db);
/// Internal (core) SQL implementation of the osquery getQueryColumns API.
Status getQueryColumnsInternal(const std::string& q, tables::TableColumns& columns);
/**
* @brief Analyze a query, providing information about the result columns
*
* This function asks SQLite to determine what the names and types are of the
* result columns of the provided query. Only table columns (not expressions or
* subqueries) can have their types determined. Types that are not determined
* are indicated with the string "UNKNOWN".
*
* @param q the query to analyze
* @param columns the vector to fill with column information
* @param db the SQLite3 database to perform the analysis on
*
* @return status indicating success or failure of the operation
*/
Status getQueryColumnsInternal(const std::string& q,
tables::TableColumns& columns,
sqlite3* db);
/**
* @brief Return a fully configured sqlite3 database object
*
* An osquery database is basically just a SQLite3 database with several
* virtual tables attached. This method is the main abstraction for creating
* SQLite3 databases within osquery.
*
* Note: osquery::initOsquery must be called before calling createDB in order
* for virtual tables to be registered.
*
* @return a SQLite3 database with all virtual tables attached
*/
sqlite3* createDB();
/**
* @brief Get a string representation of a SQLite return code
*/
std::string getStringForSQLiteReturnCode(int code);
// the callback for populating a std::vector<row> set of results. "argument"
// should be a non-const reference to a std::vector<row>
int queryDataCallback(void* argument, int argc, char* argv[], char* column[]);
}

View File

@ -0,0 +1,141 @@
/*
* 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/sql.h>
#include "osquery/core/test_util.h"
#include "osquery/sql/sqlite_util.h"
namespace osquery {
class SQLiteUtilTests : public testing::Test {};
sqlite3* createTestDB() {
sqlite3* db = createDB();
char* err = nullptr;
std::vector<std::string> queries = {
"CREATE TABLE test_table ("
"username varchar(30) primary key, "
"age int"
")",
"INSERT INTO test_table VALUES (\"mike\", 23)",
"INSERT INTO test_table VALUES (\"matt\", 24)"};
for (auto q : queries) {
sqlite3_exec(db, q.c_str(), nullptr, nullptr, &err);
if (err != nullptr) {
return nullptr;
}
}
return db;
}
TEST_F(SQLiteUtilTests, test_simple_query_execution) {
auto db = createTestDB();
QueryData results;
auto status = queryInternal(kTestQuery, results, db);
sqlite3_close(db);
EXPECT_TRUE(status.ok());
EXPECT_EQ(results, getTestDBExpectedResults());
}
TEST_F(SQLiteUtilTests, test_passing_callback_no_data_param) {
char* err = nullptr;
auto db = createTestDB();
sqlite3_exec(db, kTestQuery.c_str(), queryDataCallback, nullptr, &err);
sqlite3_close(db);
EXPECT_TRUE(err != nullptr);
if (err != nullptr) {
sqlite3_free(err);
}
}
TEST_F(SQLiteUtilTests, test_aggregate_query) {
auto db = createTestDB();
QueryData results;
auto status = queryInternal(kTestQuery, results, db);
sqlite3_close(db);
EXPECT_TRUE(status.ok());
EXPECT_EQ(results, getTestDBExpectedResults());
}
TEST_F(SQLiteUtilTests, test_get_test_db_result_stream) {
auto db = createTestDB();
auto results = getTestDBResultStream();
for (auto r : results) {
char* err_char = nullptr;
sqlite3_exec(db, (r.first).c_str(), nullptr, nullptr, &err_char);
EXPECT_TRUE(err_char == nullptr);
if (err_char != nullptr) {
sqlite3_free(err_char);
ASSERT_TRUE(false);
}
QueryData expected;
auto status = queryInternal(kTestQuery, expected, db);
EXPECT_EQ(expected, r.second);
}
sqlite3_close(db);
}
TEST_F(SQLiteUtilTests, test_get_query_columns) {
std::unique_ptr<sqlite3, decltype(sqlite3_close)*> db_managed(createDB(),
sqlite3_close);
sqlite3* db = db_managed.get();
std::string query;
Status status;
tables::TableColumns results;
query =
"SELECT hour, minutes, seconds, version, config_md5, config_path, \
pid FROM time JOIN osquery_info";
status = getQueryColumnsInternal(query, results, db);
ASSERT_TRUE(status.ok());
ASSERT_EQ(7, results.size());
EXPECT_EQ(std::make_pair(std::string("hour"), std::string("INTEGER")),
results[0]);
EXPECT_EQ(std::make_pair(std::string("minutes"), std::string("INTEGER")),
results[1]);
EXPECT_EQ(std::make_pair(std::string("seconds"), std::string("INTEGER")),
results[2]);
EXPECT_EQ(std::make_pair(std::string("version"), std::string("TEXT")),
results[3]);
EXPECT_EQ(std::make_pair(std::string("config_md5"), std::string("TEXT")),
results[4]);
EXPECT_EQ(std::make_pair(std::string("config_path"), std::string("TEXT")),
results[5]);
EXPECT_EQ(std::make_pair(std::string("pid"), std::string("INTEGER")),
results[6]);
query = "SELECT hour + 1 AS hour1, minutes + 1 FROM time";
status = getQueryColumnsInternal(query, results, db);
ASSERT_TRUE(status.ok());
ASSERT_EQ(2, results.size());
EXPECT_EQ(std::make_pair(std::string("hour1"), std::string("UNKNOWN")),
results[0]);
EXPECT_EQ(std::make_pair(std::string("minutes + 1"), std::string("UNKNOWN")),
results[1]);
query = "SELECT * FROM foo";
status = getQueryColumnsInternal(query, results, db);
ASSERT_FALSE(status.ok());
}
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -10,7 +10,7 @@
#include <osquery/logger.h>
#include "osquery/core/virtual_table.h"
#include "osquery/sql/virtual_table.h"
namespace osquery {
namespace tables {
@ -211,8 +211,7 @@ static int xFilter(sqlite3_vtab_cursor *pVtabCursor,
for (const auto &column : pVtab->content->columns) {
try {
pVtab->content->data[column.first].push_back(row.at(column.first));
}
catch (const std::out_of_range &e) {
} catch (const std::out_of_range &e) {
VLOG(1) << "Table " << pVtab->content->name << " row "
<< pVtab->content->n << " did not include column "
<< column.first;
@ -272,8 +271,7 @@ void attachVirtualTables(sqlite3 *db) {
for (const auto &name : Registry::names("table")) {
int status = attachTable(db, name);
if (status != SQLITE_OK) {
LOG(ERROR) << "Error attaching virtual table: " << name << " (" << status
<< ")";
LOG(ERROR) << "Error attaching table: " << name << " (" << status << ")";
}
}
}

View File

@ -3,17 +3,17 @@
* 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
* 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 <sqlite3.h>
#include <osquery/tables.h>
#include "osquery/sql/sqlite_util.h"
namespace osquery {
namespace tables {
@ -48,7 +48,10 @@ struct VirtualTable {
VirtualTableContent *content;
};
/// Attach a table plugin name to an in-memory SQLite datable.
int attachTable(sqlite3 *db, const std::string &name);
/// Attach all table plugins to an in-memory SQLite datable.
void attachVirtualTables(sqlite3 *db);
}
}

View File

@ -12,8 +12,9 @@
#include <osquery/core.h>
#include <osquery/registry.h>
#include <osquery/sql.h>
#include "osquery/core/virtual_table.h"
#include "osquery/sql/virtual_table.h"
namespace osquery {
namespace tables {
@ -57,8 +58,8 @@ TEST_F(VirtualTableTests, test_sqlite3_attach_vtable) {
EXPECT_EQ(rc, SQLITE_OK);
std::string q = "SELECT sql FROM sqlite_temp_master WHERE tbl_name='sample';";
int error_return;
QueryData results = query(q, error_return, db);
QueryData results;
auto status = queryInternal(q, results, db);
EXPECT_EQ("CREATE VIRTUAL TABLE sample USING sample(foo INTEGER, bar TEXT)",
results[0]["sql"]);
sqlite3_close(db);

View File

@ -1,5 +1,5 @@
if(APPLE)
ADD_OSQUERY_OBJCXX_LIBRARY(osquery_tables_objc
ADD_OSQUERY_OBJCXX_LIBRARY(FALSE osquery_tables_objc
../core/darwin/NSProcessInfo+PECocoaBackports.mm
../core/darwin/NSProcessInfo+PECocoaBackports.h
../core/darwin/PECocoaBackportsGlobal.h
@ -9,7 +9,7 @@ if(APPLE)
system/darwin/ca_certs.mm
)
ADD_OSQUERY_LIBRARY(osquery_tables_darwin
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_darwin
events/darwin/passwd_changes.cpp
events/darwin/hardware_events.cpp
networking/darwin/routes.cpp
@ -39,12 +39,12 @@ if(APPLE)
system/darwin/xattr.cpp
)
ADD_OSQUERY_LINK("-framework CoreFoundation")
ADD_OSQUERY_LINK("-framework Security")
ADD_OSQUERY_LINK("-framework OpenDirectory")
ADD_OSQUERY_LINK("-framework DiskArbitration")
ADD_OSQUERY_LINK(FALSE "-framework CoreFoundation")
ADD_OSQUERY_LINK(FALSE "-framework Security")
ADD_OSQUERY_LINK(FALSE "-framework OpenDirectory")
ADD_OSQUERY_LINK(FALSE "-framework DiskArbitration")
elseif(FREEBSD)
ADD_OSQUERY_LIBRARY(osquery_tables_freebsd
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_freebsd
events/freebsd/passwd_changes.cpp
networking/freebsd/routes.cpp
system/freebsd/processes.cpp
@ -52,7 +52,7 @@ elseif(FREEBSD)
system/freebsd/groups.cpp
)
else()
ADD_OSQUERY_LIBRARY(osquery_tables_linux
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_linux
events/linux/hardware_events.cpp
events/linux/passwd_changes.cpp
networking/linux/arp_cache.cpp
@ -75,30 +75,30 @@ else()
if(CENTOS)
# CentOS specific tables
ADD_OSQUERY_LIBRARY(osquery_tables_redhat
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_redhat
system/linux/rpm_packages.cpp
)
ADD_OSQUERY_LINK("rpm")
ADD_OSQUERY_LINK("rpmio")
ADD_OSQUERY_LINK(FALSE "rpm")
ADD_OSQUERY_LINK(FALSE "rpmio")
elseif(UBUNTU)
# Ubuntu specific tables
ADD_OSQUERY_LIBRARY(osquery_tables_ubuntu
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_ubuntu
system/linux/deb_packages.cpp
system/linux/apt_sources.cpp
)
ADD_OSQUERY_LINK("apt-pkg")
ADD_OSQUERY_LINK("dpkg")
ADD_OSQUERY_LINK(FALSE "apt-pkg")
ADD_OSQUERY_LINK(FALSE "dpkg")
endif()
ADD_OSQUERY_LINK("procps" "proc")
ADD_OSQUERY_LINK("blkid")
ADD_OSQUERY_LINK("udev")
ADD_OSQUERY_LINK("uuid")
ADD_OSQUERY_LINK(FALSE "procps" "proc")
ADD_OSQUERY_LINK(FALSE "blkid")
ADD_OSQUERY_LINK(FALSE "udev")
ADD_OSQUERY_LINK(FALSE "uuid")
endif()
ADD_OSQUERY_LIBRARY(osquery_tables
ADD_OSQUERY_LIBRARY(FALSE osquery_tables
networking/etc_hosts.cpp
networking/etc_services.cpp
networking/interfaces.cpp
@ -113,18 +113,18 @@ ADD_OSQUERY_LIBRARY(osquery_tables
system/logged_in_users.cpp
)
ADD_OSQUERY_CORE_LIBRARY(osquery_utility_tables
ADD_OSQUERY_LIBRARY(TRUE osquery_utility_tables
utility/time.cpp
utility/hash.cpp
utility/file.cpp
utility/osquery.cpp
)
ADD_OSQUERY_TEST(etc_hosts_tests networking/etc_hosts_tests.cpp TRUE)
ADD_OSQUERY_TEST(FALSE etc_hosts_tests networking/etc_hosts_tests.cpp)
if(APPLE)
ADD_OSQUERY_TEST(xattr_tests system/darwin/xattr_tests.cpp TRUE)
ADD_OSQUERY_TEST(apps_tests system/darwin/apps_tests.cpp TRUE)
ADD_OSQUERY_TEST(ca_certs_tests system/darwin/ca_certs_tests.cpp TRUE)
ADD_OSQUERY_TEST(firewall_tests system/darwin/firewall_tests.cpp TRUE)
ADD_OSQUERY_TEST(launchd_tests system/darwin/launchd_tests.cpp TRUE)
ADD_OSQUERY_TEST(FALSE xattr_tests system/darwin/xattr_tests.cpp)
ADD_OSQUERY_TEST(FALSE apps_tests system/darwin/apps_tests.cpp)
ADD_OSQUERY_TEST(FALSE ca_certs_tests system/darwin/ca_certs_tests.cpp)
ADD_OSQUERY_TEST(FALSE firewall_tests system/darwin/firewall_tests.cpp)
ADD_OSQUERY_TEST(FALSE launchd_tests system/darwin/launchd_tests.cpp)
endif()

View File

@ -15,8 +15,6 @@
#include <osquery/events.h>
#include <osquery/tables.h>
#include "osquery/core/virtual_table.h"
namespace osquery { namespace tables {
{% for table in tables %}
{{table}}

View File

@ -15,8 +15,6 @@
#include <osquery/events.h>
#include <osquery/tables.h>
#include "osquery/core/virtual_table.h"
namespace osquery { namespace tables {
/// BEGIN[GENTABLE]