Merge branch 'master' of github.com:facebook/osquery into 520_pt_json_workaround

This commit is contained in:
Bryan Eastes 2014-12-20 18:24:33 -08:00
commit 93cb303abc
217 changed files with 4548 additions and 1740 deletions

View File

@ -204,6 +204,7 @@ cpp_library(
srcs=[
"osquery/tables/events/linux/passwd_changes.cpp",
"osquery/tables/networking/etc_hosts.cpp",
"osquery/tables/networking/etc_services.cpp",
"osquery/tables/networking/utils.cpp",
"osquery/tables/networking/linux/arp_cache.cpp",
"osquery/tables/networking/linux/port_inode.cpp",

View 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
@ -118,6 +126,13 @@ class Config {
*/
static int splayValue(int original, int splayPercent);
/**
* @brief Calculate the has of the osquery config
*
* @return The MD5 of the osquery config
*/
Status getMD5(std::string& hashString);
private:
/**
* @brief Default constructor.
@ -146,6 +161,27 @@ 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

View 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

View 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

View 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

View 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;
};
}

View 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

View 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
@ -359,4 +367,4 @@ bool addUniqueRowToQueryData(QueryData& q, const Row& r);
* @param newData the new escaped QueryData object
*/
void escapeQueryData(const osquery::QueryData &oldData, osquery::QueryData &newData);
}
}

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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); \
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -1,8 +1,6 @@
SET(OSQUERY_LIBS
readline
pthread
crypto
ssl
)
SET(OSQUERY_APPLE_LIBS
@ -17,6 +15,8 @@ SET(OSQUERY_APPLE_LIBS
/usr/local/lib/liblz4.a
/usr/local/lib/libgflags.a
/usr/local/lib/libglog.a
/usr/local/opt/openssl/lib/libcrypto.a
/usr/local/opt/openssl/lib/libssl.a
dl
bz2
z
@ -38,6 +38,8 @@ SET(OSQUERY_LINUX_LIBS
blkid
rt
dl
crypto
ssl
)
SET(OSQUERY_UBUNTU_LIBS
@ -71,6 +73,8 @@ SET(OSQUERY_FREEBSD_LIBS
snappy
unwind
lzma
crypto
ssl
)
# Check for the explicit path to determine the version of procps

View 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 <future>
@ -18,6 +26,8 @@
#include <osquery/flags.h>
#include <osquery/status.h>
#include "osquery/core/md5.h"
using osquery::Status;
namespace pt = boost::property_tree;
@ -71,10 +81,7 @@ Config::Config() {
cfg_ = conf;
}
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";
@ -85,7 +92,20 @@ Status Config::genConfig(OsqueryConfig& conf) {
if (!config_data.first.ok()) {
return config_data.first;
}
json << config_data.second;
conf = config_data.second;
return Status(0, "OK");
}
Status Config::genConfig(OsqueryConfig& conf) {
std::stringstream json;
pt::ptree tree;
std::string config_string;
auto s = genConfig(config_string);
if (!s.ok()) {
return s;
}
json << config_string;
pt::read_json(json, tree);
try {
@ -135,4 +155,17 @@ int Config::splayValue(int original, int splayPercent) {
std::uniform_int_distribution<int> distribution(min_value, max_value);
return distribution(generator);
}
Status Config::getMD5(std::string& hashString) {
std::string config_string;
auto s = genConfig(config_string);
if (!s.ok()) {
return s;
}
osquery::md5::MD5 digest;
hashString = std::string(digest.digestString(config_string.c_str()));
return Status(0, "OK");
}
}

View 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>

View 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/config/plugin.h>

View 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>

View 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 <glog/logging.h>

View File

@ -1,10 +1,13 @@
if(APPLE)
set (OS_CORE_SOURCE darwin/test_util.cpp darwin/test_util.h)
set (OS_CORE_SOURCE
darwin/conversions.cpp
)
else()
set (OS_CORE_SOURCE "")
endif()
ADD_OSQUERY_LIBRARY(osquery_core
conversions.cpp
init_osquery.cpp
sql.cpp
sqlite_util.cpp

View File

@ -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();
}
}

View 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,6 +15,10 @@
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#ifdef DARWIN
#include <CoreFoundation/CoreFoundation.h>
#endif
namespace osquery {
template <typename T>
@ -32,4 +44,26 @@ typename boost::shared_ptr<T> std_to_boost_shared_ptr(
typename std::shared_ptr<T> const& p) {
return boost::shared_ptr<T>(p.get(), boost::bind(&do_release_std<T>, p, _1));
}
/**
* @brief Decode a base64 encoded string.
*
* @param encoded The encode base64 string.
* @return Decoded string.
*/
std::string base64Decode(const std::string& encoded);
#ifdef DARWIN
/**
* @brief Convert a CFStringRef to a std::string.
*/
std::string stringFromCFString(const CFStringRef& cf_string);
/**
* @brief Convert a CFNumberRef to a std::string.
*/
std::string stringFromCFNumber(const CFDataRef& cf_number);
std::string stringFromCFData(const CFDataRef& cf_data);
#endif
}

View 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>

View File

@ -0,0 +1,61 @@
/*
* 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/lexical_cast.hpp>
#include "osquery/core/conversions.h"
namespace osquery {
std::string stringFromCFString(const CFStringRef& cf_string) {
// Access, then convert the CFString. CFStringGetCStringPtr is less-safe.
CFIndex length = CFStringGetLength(cf_string);
char* buffer = (char*)malloc(length + 1);
if (!CFStringGetCString(
cf_string, buffer, length + 1, kCFStringEncodingASCII)) {
free(buffer);
return "";
}
// Cleanup allocations.
std::string result(buffer);
free(buffer);
return result;
}
std::string stringFromCFData(const CFDataRef& cf_data) {
CFRange range = CFRangeMake(0, CFDataGetLength(cf_data));
char* buffer = (char*)malloc(range.length + 1);
memset(buffer, 0, range.length + 1);
CFDataGetBytes(cf_data, range, (UInt8*)buffer);
for (CFIndex i = 0; i < range.length; ++i) {
if (buffer[i] == 0) {
buffer[i] = ' ';
}
}
// Cleanup allocations.
std::string result(buffer);
free(buffer);
return result;
}
std::string stringFromCFNumber(const CFDataRef& cf_number) {
unsigned int value;
if (CFGetTypeID(cf_number) != CFNumberGetTypeID() ||
!CFNumberGetValue((CFNumberRef)cf_number, kCFNumberIntType, &value)) {
return "0";
}
// Cast as a string.
return boost::lexical_cast<std::string>(value);
}
}

View File

@ -1,371 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "osquery/core/darwin/test_util.h"
#include <boost/property_tree/json_parser.hpp>
namespace pt = boost::property_tree;
namespace osquery {
namespace core {
std::string getPlistContent() {
std::string content = R"(
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<true/>
<key>Label</key>
<string>com.apple.FileSyncAgent.sshd</string>
<key>ProgramArguments</key>
<array>
<string>/System/Library/CoreServices/FileSyncAgent.app/Contents/Resources/FileSyncAgent_sshd-keygen-wrapper</string>
<string>-i</string>
<string>-f</string>
<string>/System/Library/CoreServices/FileSyncAgent.app/Contents/Resources/FileSyncAgent_sshd_config</string>
</array>
<key>SessionCreate</key>
<true/>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>appleugcontrol</string>
<key>Bonjour</key>
<true/>
</dict>
</dict>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>
)";
return content;
}
std::string getALFContent() {
std::string content = R"(
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>allowsignedenabled</key>
<integer>1</integer>
<key>applications</key>
<array/>
<key>exceptions</key>
<array>
<dict>
<key>path</key>
<string>/usr/libexec/configd</string>
<key>state</key>
<integer>3</integer>
</dict>
<dict>
<key>path</key>
<string>/usr/sbin/mDNSResponder</string>
<key>state</key>
<integer>3</integer>
</dict>
<dict>
<key>path</key>
<string>/usr/sbin/racoon</string>
<key>state</key>
<integer>3</integer>
</dict>
<dict>
<key>path</key>
<string>/usr/bin/nmblookup</string>
<key>state</key>
<integer>3</integer>
</dict>
<dict>
<key>path</key>
<string>/System/Library/PrivateFrameworks/Admin.framework/Versions/A/Resources/readconfig</string>
<key>state</key>
<integer>3</integer>
</dict>
</array>
<key>explicitauths</key>
<array>
<dict>
<key>id</key>
<string>org.python.python.app</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.ruby</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.a2p</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.javajdk16.cmd</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.php</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.nc</string>
</dict>
<dict>
<key>id</key>
<string>com.apple.ksh</string>
</dict>
</array>
<key>firewall</key>
<dict>
<key>Apple Remote Desktop</key>
<dict>
<key>proc</key>
<string>AppleVNCServer</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>FTP Access</key>
<dict>
<key>proc</key>
<string>ftpd</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>ODSAgent</key>
<dict>
<key>proc</key>
<string>ODSAgent</string>
<key>servicebundleid</key>
<string>com.apple.ODSAgent</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Personal File Sharing</key>
<dict>
<key>proc</key>
<string>AppleFileServer</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Personal Web Sharing</key>
<dict>
<key>proc</key>
<string>httpd</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Printer Sharing</key>
<dict>
<key>proc</key>
<string>cupsd</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Remote Apple Events</key>
<dict>
<key>proc</key>
<string>AEServer</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Remote Login - SSH</key>
<dict>
<key>proc</key>
<string>sshd-keygen-wrapper</string>
<key>state</key>
<integer>0</integer>
</dict>
<key>Samba Sharing</key>
<dict>
<key>proc</key>
<string>smbd</string>
<key>state</key>
<integer>0</integer>
</dict>
</dict>
<key>firewallunload</key>
<integer>0</integer>
<key>globalstate</key>
<integer>0</integer>
<key>loggingenabled</key>
<integer>0</integer>
<key>loggingoption</key>
<integer>0</integer>
<key>stealthenabled</key>
<integer>0</integer>
<key>version</key>
<string>1.0a25</string>
</dict>
</plist>
)";
return content;
}
pt::ptree getALFTree() {
auto content = getALFContent();
pt::ptree tree;
parsePlistContent(content, tree);
return tree;
}
std::string getInfoPlistContent() {
std::string content = R"(
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>13C23</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>Photo Booth</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>PBLibraryIcon</string>
<key>CFBundleTypeName</key>
<string>Photo Booth Library</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>PBLb</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSTypeIsPackage</key>
<true/>
<key>NSDocumentClass</key>
<string>ArchiveDocument</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>Photo Booth</string>
<key>CFBundleHelpBookFolder</key>
<string>PhotoBooth.help</string>
<key>CFBundleHelpBookName</key>
<string>com.apple.PhotoBooth.help</string>
<key>CFBundleIconFile</key>
<string>PhotoBooth.icns</string>
<key>CFBundleIdentifier</key>
<string>com.apple.PhotoBooth</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>6.0</string>
<key>CFBundleSignature</key>
<string>PhBo</string>
<key>CFBundleVersion</key>
<string>517</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>5A2053</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>13C23</string>
<key>DTSDKName</key>
<string></string>
<key>DTXcode</key>
<string>0501</string>
<key>DTXcodeBuild</key>
<string>5A2053</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.entertainment</string>
<key>LSMinimumSystemVersion</key>
<string>10.7.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>PBApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<key>NSSupportsSuddenTermination</key>
<string>YES</string>
</dict>
</plist>
)";
return content;
}
std::string getLaunchdContent() {
std::string content = R"(
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.mDNSResponder</string>
<key>OnDemand</key>
<false/>
<key>InitGroups</key>
<false/>
<key>UserName</key>
<string>_mdnsresponder</string>
<key>GroupName</key>
<string>_mdnsresponder</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/mDNSResponder</string>
</array>
<key>MachServices</key>
<dict>
<key>com.apple.mDNSResponder</key>
<true/>
<key>com.apple.mDNSResponder.dnsproxy</key>
<true/>
</dict>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockFamily</key>
<string>Unix</string>
<key>SockPathName</key>
<string>/var/run/mDNSResponder</string>
<key>SockPathMode</key>
<integer>438</integer>
</dict>
</dict>
<key>EnableTransactions</key>
<true/>
<key>BeginTransactionAtShutdown</key>
<true/>
<key>POSIXSpawnType</key>
<string>Interactive</string>
</dict>
</plist>
)";
return content;
}
pt::ptree getInfoPlistTree() {
auto content = getInfoPlistContent();
pt::ptree tree;
parsePlistContent(content, tree);
return tree;
}
pt::ptree getLaunchdTree() {
auto content = getLaunchdContent();
pt::ptree tree;
parsePlistContent(content, tree);
return tree;
}
}
}

View File

@ -1,31 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include "osquery/core/test_util.h"
namespace osquery {
namespace core {
// generate test content of a property list
std::string getPlistContent();
// generate test content of com.apple.alf
std::string getALFcontent();
// generate a test ptree of the content returned by getALFContent
boost::property_tree::ptree getALFTree();
// generate test content of an Info.plist file
std::string getInfoPlistContent();
// generate a test ptree of the content returned by getInfoPlistContent
boost::property_tree::ptree getInfoPlistTree();
// generate test content for a LaunchDaemon
std::string getLaunchdContent();
// generate a test ptree of the content returned by getLaunchdContent
boost::property_tree::ptree getLaunchdTree();
}
}

View 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",
" --%s=%s\n %s\n",
flag.first.c_str(),
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());
}
}
}

View 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 <syslog.h>
#include <glog/logging.h>
@ -31,43 +41,52 @@ 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]) : "";
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;

View 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>

View 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>

View 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/database.h>
#include <osquery/logger.h>

View 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

View 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>
#include "osquery/core/sqlite_util.h"

View 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>

View 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>

View 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>

View File

@ -1,6 +1,12 @@
// 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>
@ -9,15 +15,18 @@
#include <glog/logging.h>
#include "osquery/core/sqlite_util.h"
#include <osquery/filesystem.h>
#include "osquery/core/sqlite_util.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 +235,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;
}

View 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
@ -22,6 +30,7 @@ namespace core {
// 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

View 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>
#include <glog/logging.h>

View 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>

View 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>

View 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/core/virtual_table.h"

View 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
@ -70,7 +78,7 @@ class TablePlugin {
virtual ~TablePlugin(){};
protected:
TablePlugin(){};
TablePlugin() { n = 0; };
};
typedef std::shared_ptr<TablePlugin> TablePluginRef;

View 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 <mutex>

View 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>

View 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>

View 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>

View 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>

View 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>
#include <string>

View 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 <iostream>
#include <sstream>

View 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>
#include <glog/logging.h>

View 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 <glog/logging.h>

View 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>

View File

@ -6,6 +6,7 @@ if(APPLE)
ADD_OSQUERY_LIBRARY(osquery_events_darwin
darwin/fsevents.cpp
darwin/iokit_hid.cpp
darwin/scnetwork.cpp
)
elseif(FREEBSD)

View 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/numeric/ublas/matrix.hpp>
@ -102,13 +110,13 @@ void FSEventsEventPublisher::tearDown() {
void FSEventsEventPublisher::configure() {
// Rebuild the watch paths.
paths_.clear();
for (auto& subscription : subscriptions_) {
for (const auto& subscription : subscriptions_) {
auto fs_subscription = getSubscriptionContext(subscription->context);
paths_.insert(fs_subscription->path);
}
// There were no paths in the subscriptions?
if (paths_.size() == 0) {
if (paths_.empty()) {
return;
}
@ -154,8 +162,9 @@ void FSEventsEventPublisher::Callback(
}
}
bool FSEventsEventPublisher::shouldFire(const FSEventsSubscriptionContextRef mc,
const FSEventsEventContextRef ec) {
bool FSEventsEventPublisher::shouldFire(
const FSEventsSubscriptionContextRef& mc,
const FSEventsEventContextRef& ec) {
ssize_t found = ec->path.find(mc->path);
if (found != 0) {
return false;

View 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
@ -56,10 +64,9 @@ typedef std::shared_ptr<FSEventsSubscriptionContext>
* preferred implementation of FSEvents handling.
*
*/
class FSEventsEventPublisher : public EventPublisher {
DECLARE_EVENTPUBLISHER(FSEventsEventPublisher,
FSEventsSubscriptionContext,
FSEventsEventContext)
class FSEventsEventPublisher
: public EventPublisher<FSEventsSubscriptionContext, FSEventsEventContext> {
DECLARE_PUBLISHER("FSEventsEventPublisher");
public:
void configure();
@ -78,10 +85,14 @@ class FSEventsEventPublisher : public EventPublisher {
const FSEventStreamEventId fsevent_ids[]);
public:
FSEventsEventPublisher()
: EventPublisher(), stream_(nullptr), run_loop_(nullptr) {}
bool shouldFire(const FSEventsSubscriptionContextRef mc,
const FSEventsEventContextRef ec);
FSEventsEventPublisher() : EventPublisher() {
stream_started_ = false;
stream_ = nullptr;
run_loop_ = nullptr;
}
bool shouldFire(const FSEventsSubscriptionContextRef& mc,
const FSEventsEventContextRef& ec);
private:
// Restart the run loop.

View 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>
@ -35,14 +43,6 @@ class FSEventsTests : public testing::Test {
temp_thread_ = boost::thread(EventFactory::run, "FSEventsEventPublisher");
}
void SubscriptionAction(uint32_t mask = 0, EventCallback ec = 0) {
auto mc = std::make_shared<FSEventsSubscriptionContext>();
mc->path = kRealTestPath;
mc->mask = mask;
EventFactory::addSubscription("FSEventsEventPublisher", mc, ec);
}
void WaitForStream(int max) {
int delay = 0;
while (delay < max * 1000) {
@ -171,22 +171,29 @@ TEST_F(FSEventsTests, test_fsevents_run) {
EventFactory::end(false);
}
class TestFSEventsEventSubscriber : public EventSubscriber {
DECLARE_EVENTSUBSCRIBER(TestFSEventsEventSubscriber, FSEventsEventPublisher);
DECLARE_CALLBACK(SimpleCallback, FSEventsEventContext);
DECLARE_CALLBACK(Callback, FSEventsEventContext);
class TestFSEventsEventSubscriber
: public EventSubscriber<FSEventsEventPublisher> {
DECLARE_SUBSCRIBER("TestFSEventsEventSubscriber");
public:
void init() { callback_count_ = 0; }
Status SimpleCallback(const FSEventsEventContextRef ec) {
Status SimpleCallback(const FSEventsEventContextRef& ec) {
callback_count_ += 1;
return Status(0, "OK");
}
Status Callback(const FSEventsEventContextRef ec) {
Row r;
r["action"] = ec->action;
r["path"] = ec->path;
SCRef GetSubscription(uint32_t mask = 0) {
auto sc = createSubscriptionContext();
sc->path = kRealTestPath;
sc->mask = mask;
return sc;
}
Status Callback(const FSEventsEventContextRef& 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);
@ -194,10 +201,10 @@ class TestFSEventsEventSubscriber : public EventSubscriber {
return Status(0, "OK");
}
static void WaitForEvents(int max) {
void WaitForEvents(int max) {
int delay = 0;
while (delay < max * 1000) {
if (getInstance()->callback_count_ > 0) {
if (callback_count_ > 0) {
return;
}
::usleep(50);
@ -213,18 +220,23 @@ class TestFSEventsEventSubscriber : public EventSubscriber {
TEST_F(FSEventsTests, test_fsevents_fire_event) {
// Assume event type is registered.
StartEventLoop();
TestFSEventsEventSubscriber::getInstance()->init();
// Simulate registering an event subscriber.
auto sub = std::make_shared<TestFSEventsEventSubscriber>();
sub->init();
// Create a subscriptioning context, note the added Event to the symbol
SubscriptionAction(0, TestFSEventsEventSubscriber::EventSimpleCallback);
auto sc = sub->GetSubscription(0);
sub->subscribe(&TestFSEventsEventSubscriber::SimpleCallback, sc);
// SubscriptionAction(0, TestFSEventsEventSubscriber::EventSimpleCallback);
CreateEvents();
// This time wait for the callback.
TestFSEventsEventSubscriber::WaitForEvents(kMaxEventLatency);
sub->WaitForEvents(kMaxEventLatency);
// Make sure our expected event fired (aka subscription callback was called).
EXPECT_TRUE(TestFSEventsEventSubscriber::getInstance()->callback_count_ > 0);
EXPECT_TRUE(sub->callback_count_ > 0);
// Cause the thread to tear down.
EndEventLoop();
@ -233,18 +245,22 @@ TEST_F(FSEventsTests, test_fsevents_fire_event) {
TEST_F(FSEventsTests, test_fsevents_event_action) {
// Assume event type is registered.
StartEventLoop();
TestFSEventsEventSubscriber::getInstance()->init();
SubscriptionAction(0, TestFSEventsEventSubscriber::EventCallback);
// Simulate registering an event subscriber.
auto sub = std::make_shared<TestFSEventsEventSubscriber>();
sub->init();
auto sc = sub->GetSubscription(0);
sub->subscribe(&TestFSEventsEventSubscriber::Callback, sc);
// SubscriptionAction(0, TestFSEventsEventSubscriber::EventCallback);
CreateEvents();
TestFSEventsEventSubscriber::WaitForEvents(kMaxEventLatency);
sub->WaitForEvents(kMaxEventLatency);
// Make sure the fsevents action was expected.
const auto& event_module = TestFSEventsEventSubscriber::getInstance();
EXPECT_TRUE(event_module->actions_.size() > 0);
if (event_module->actions_.size() > 1) {
EXPECT_EQ(event_module->actions_[0], "UPDATED");
EXPECT_TRUE(sub->actions_.size() > 0);
if (sub->actions_.size() > 1) {
EXPECT_EQ(sub->actions_[0], "UPDATED");
}
// Cause the thread to tear down.

View File

@ -0,0 +1,195 @@
/*
* 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>
#include "osquery/core/conversions.h"
#include "osquery/events/darwin/iokit_hid.h"
namespace osquery {
REGISTER_EVENTPUBLISHER(IOKitHIDEventPublisher);
size_t IOKitHIDEventPublisher::initial_device_count_ = 0;
size_t IOKitHIDEventPublisher::initial_device_evented_count_ = 0;
boost::mutex IOKitHIDEventPublisher::iokit_match_lock_;
std::string IOKitHIDEventPublisher::getProperty(const IOHIDDeviceRef &device,
const CFStringRef &property) {
CFTypeRef value = IOHIDDeviceGetProperty(device, property);
if (value == NULL) {
return "";
}
// Only support CFNumber and CFString types.
if (CFGetTypeID(value) == CFNumberGetTypeID()) {
return stringFromCFNumber((CFDataRef)value);
} else if (CFGetTypeID(value) == CFStringGetTypeID()) {
return stringFromCFString((CFStringRef)value);
}
return "";
}
void IOKitHIDEventPublisher::restart() {
if (run_loop_ == nullptr) {
// There is no run loop to restart.
return;
}
// Remove any existing stream.
stop();
if (manager_ == nullptr) {
manager_ = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
}
// Match anything.
IOHIDManagerSetDeviceMatching(manager_, NULL);
auto status = IOHIDManagerOpen(manager_, kIOHIDOptionsTypeNone);
if (status != kIOReturnSuccess) {
LOG(ERROR) << "Cannot open IOKit HID Manager";
return;
}
// Enumerate initial set of devices matched before time=0.
CFSetRef devices = IOHIDManagerCopyDevices(manager_);
initial_device_count_ = devices == NULL ? 0 : CFSetGetCount(devices);
CFRelease(devices);
// Register callbacks.
IOHIDManagerRegisterDeviceMatchingCallback(
manager_, IOKitHIDEventPublisher::MatchingCallback, NULL);
IOHIDManagerRegisterDeviceRemovalCallback(
manager_, IOKitHIDEventPublisher::RemovalCallback, NULL);
IOHIDManagerScheduleWithRunLoop(manager_, run_loop_, kCFRunLoopDefaultMode);
manager_started_ = true;
}
void IOKitHIDEventPublisher::MatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device) {
{
// Must not event on initial list of matches.
boost::lock_guard<boost::mutex> lock(iokit_match_lock_);
if (initial_device_count_ > initial_device_evented_count_) {
initial_device_evented_count_++;
return;
}
}
fire(device, "add");
}
void IOKitHIDEventPublisher::fire(const IOHIDDeviceRef &device,
const std::string &action) {
auto ec = createEventContext();
ec->device = device;
ec->action = action;
// Fill in more-useful fields.
ec->vendor_id = getProperty(device, CFSTR(kIOHIDVendorIDKey));
ec->model_id = getProperty(device, CFSTR(kIOHIDProductIDKey));
ec->vendor = getProperty(device, CFSTR(kIOHIDManufacturerKey));
ec->model = getProperty(device, CFSTR(kIOHIDProductKey));
ec->transport = getProperty(device, CFSTR(kIOHIDTransportKey));
ec->primary_usage = getProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
ec->device_usage = getProperty(device, CFSTR(kIOHIDDeviceUsageKey));
// Fill in more esoteric properties.
ec->version = getProperty(device, CFSTR(kIOHIDVersionNumberKey));
ec->location = getProperty(device, CFSTR(kIOHIDLocationIDKey));
ec->serial = getProperty(device, CFSTR(kIOHIDSerialNumberKey));
ec->country_code = getProperty(device, CFSTR(kIOHIDCountryCodeKey));
EventFactory::fire<IOKitHIDEventPublisher>(ec);
}
void IOKitHIDEventPublisher::RemovalCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device) {
fire(device, "remove");
}
void IOKitHIDEventPublisher::InputValueCallback(void *context,
IOReturn result,
void *sender,
IOHIDValueRef value) {
// Nothing yet (do not allow value change subscriptions).
// Value changes contain potentially sensitive data.
}
bool IOKitHIDEventPublisher::shouldFire(
const IOKitHIDSubscriptionContextRef &sc,
const IOKitHIDEventContextRef &ec) {
if (sc->values) {
// See InputValueCallback
return false;
}
if (sc->transport != "" && sc->transport != ec->transport) {
return false;
} else if (sc->model_id != "" && sc->model_id != ec->model_id) {
return false;
} else if (sc->vendor_id != "" && sc->vendor_id != ec->vendor_id) {
return false;
} else if (sc->primary_usage != "" &&
sc->primary_usage != ec->primary_usage) {
return false;
} else if (sc->device_usage != "" && sc->device_usage != ec->device_usage) {
return false;
}
return true;
}
Status IOKitHIDEventPublisher::run() {
// The run entrypoint executes in a dedicated thread.
if (run_loop_ == nullptr) {
run_loop_ = CFRunLoopGetCurrent();
// Restart the stream creation.
restart();
}
// Start the run loop, it may be removed with a tearDown.
CFRunLoopRun();
// Add artificial latency to run loop.
::sleep(1);
return Status(0, "OK");
}
void IOKitHIDEventPublisher::stop() {
// Stop the manager.
if (manager_ != nullptr) {
IOHIDManagerUnscheduleFromRunLoop(
manager_, run_loop_, kCFRunLoopDefaultMode);
IOHIDManagerClose(manager_, kIOHIDOptionsTypeNone);
manager_started_ = false;
manager_ = nullptr;
}
// Stop the run loop.
if (run_loop_ != nullptr) {
CFRunLoopStop(run_loop_);
}
}
void IOKitHIDEventPublisher::tearDown() {
stop();
// Do not keep a reference to the run loop.
run_loop_ = nullptr;
}
}

View File

@ -0,0 +1,149 @@
/*
* 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 <CoreServices/CoreServices.h>
#include <IOKit/hid/IOHIDLib.h>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <osquery/events.h>
#include <osquery/status.h>
namespace osquery {
struct IOKitHIDSubscriptionContext : public SubscriptionContext {
/// Bus type, e.g., USB.
std::string transport;
/// Product name
std::string model_id;
std::string vendor_id;
/// Usage types.
std::string primary_usage;
std::string device_usage;
/// Get values from HID events.
bool values;
/// Do not request values by default.
IOKitHIDSubscriptionContext() : values(false) {}
};
struct IOKitHIDEventContext : public EventContext {
/// The native IOKit device reference.
IOHIDDeviceRef device;
/// The event action: add, remove, value change.
std::string action;
/// If a value was changed, include the result (optional).
std::string result;
/// The publisher pre-populates several fields.
std::string vendor_id;
std::string model_id;
std::string vendor;
std::string model;
std::string transport;
std::string primary_usage;
std::string device_usage;
/// More esoteric properties.
std::string version;
std::string location;
std::string serial;
std::string country_code;
};
typedef std::shared_ptr<IOKitHIDEventContext> IOKitHIDEventContextRef;
typedef std::shared_ptr<IOKitHIDSubscriptionContext>
IOKitHIDSubscriptionContextRef;
/**
* @brief An osquery EventPublisher for the Apple IOKit HID notification API.
*
*/
class IOKitHIDEventPublisher
: public EventPublisher<IOKitHIDSubscriptionContext, IOKitHIDEventContext> {
DECLARE_PUBLISHER("IOKitHIDEventPublisher");
public:
void configure() {}
void tearDown();
// Entrypoint to the run loop
Status run();
public:
/// IOKit HID hotplugged event.
static void MatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
/// IOKit HID device removed.
static void RemovalCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
/// IOKit HID device value changed.
static void InputValueCallback(void *context,
IOReturn result,
void *sender,
IOHIDValueRef value);
private:
/// Helper fire fuction to parse properties/actions.
static void fire(const IOHIDDeviceRef &device, const std::string &action);
public:
IOKitHIDEventPublisher() : EventPublisher() {
manager_started_ = false;
manager_ = nullptr;
run_loop_ = nullptr;
}
bool shouldFire(const IOKitHIDSubscriptionContextRef &mc,
const IOKitHIDEventContextRef &ec);
public:
/**
* @brief Get a string representation from an IOKitHID device property.
*
* @param device The IOKitHID device from a callback or matching query.
* @param property The device property key from <IOKit/hid/IOHIDKeys.h>.
*
* @return A string representation of the string/number, blank if missing.
*/
static std::string getProperty(const IOHIDDeviceRef &device,
const CFStringRef &property);
private:
/// Restart the run loop.
void restart();
/// Stop the manager and the run loop.
void stop();
private:
IOHIDManagerRef manager_;
bool manager_started_;
private:
CFRunLoopRef run_loop_;
private:
static size_t initial_device_count_;
static size_t initial_device_evented_count_;
static boost::mutex iokit_match_lock_;
};
}

View 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 <arpa/inet.h>
#include <netinet/in.h>
@ -23,7 +31,7 @@ void SCNetworkEventPublisher::tearDown() {
contexts_.clear();
}
void SCNetworkEventPublisher::Callback(SCNetworkReachabilityRef target,
void SCNetworkEventPublisher::Callback(const SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void* info) {
auto ec = createEventContext();
@ -32,15 +40,15 @@ void SCNetworkEventPublisher::Callback(SCNetworkReachabilityRef target,
}
bool SCNetworkEventPublisher::shouldFire(
const SCNetworkSubscriptionContextRef sc,
const SCNetworkEventContextRef ec) {
const SCNetworkSubscriptionContextRef& sc,
const SCNetworkEventContextRef& ec) {
// Only fire the event for the subscription context it matched.
return (sc == ec->subscription);
}
void SCNetworkEventPublisher::addTarget(
const SCNetworkSubscriptionContextRef sc,
const SCNetworkReachabilityRef target) {
const SCNetworkSubscriptionContextRef& sc,
const SCNetworkReachabilityRef& target) {
targets_.push_back(target);
// Assign a context (the subscription context) to the target.
@ -55,14 +63,14 @@ void SCNetworkEventPublisher::addTarget(
}
void SCNetworkEventPublisher::addHostname(
const SCNetworkSubscriptionContextRef sc) {
const SCNetworkSubscriptionContextRef& sc) {
auto target = SCNetworkReachabilityCreateWithName(NULL, sc->target.c_str());
target_names_.push_back(sc->target);
addTarget(sc, target);
}
void SCNetworkEventPublisher::addAddress(
const SCNetworkSubscriptionContextRef sc) {
const SCNetworkSubscriptionContextRef& sc) {
struct sockaddr* addr;
if (sc->family == AF_INET) {
struct sockaddr_in ipv4_addr;

View 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
@ -42,10 +50,10 @@ typedef std::shared_ptr<SCNetworkEventContext> SCNetworkEventContextRef;
* This exposes a lightweight network change monitoring capability.
*
*/
class SCNetworkEventPublisher : public EventPublisher {
DECLARE_EVENTPUBLISHER(SCNetworkEventPublisher,
SCNetworkSubscriptionContext,
SCNetworkEventContext)
class SCNetworkEventPublisher
: public EventPublisher<SCNetworkSubscriptionContext,
SCNetworkEventContext> {
DECLARE_PUBLISHER("SCNetworkEventPublisher");
public:
void configure();
@ -56,14 +64,14 @@ class SCNetworkEventPublisher : public EventPublisher {
public:
/// SCNetwork registers a client callback instead of using a select/poll loop.
static void Callback(SCNetworkReachabilityRef target,
static void Callback(const SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void* info);
public:
SCNetworkEventPublisher() : EventPublisher(), run_loop_(nullptr) {}
bool shouldFire(const SCNetworkSubscriptionContextRef sc,
const SCNetworkEventContextRef ec);
bool shouldFire(const SCNetworkSubscriptionContextRef& sc,
const SCNetworkEventContextRef& ec);
private:
// Restart the run loop by calling configure.
@ -72,10 +80,10 @@ class SCNetworkEventPublisher : public EventPublisher {
void stop();
private:
void addHostname(const SCNetworkSubscriptionContextRef sc);
void addAddress(const SCNetworkSubscriptionContextRef sc);
void addTarget(const SCNetworkSubscriptionContextRef sc,
const SCNetworkReachabilityRef target);
void addHostname(const SCNetworkSubscriptionContextRef& sc);
void addAddress(const SCNetworkSubscriptionContextRef& sc);
void addTarget(const SCNetworkSubscriptionContextRef& sc,
const SCNetworkReachabilityRef& target);
private:
std::vector<std::string> target_names_;

View 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/algorithm/string/classification.hpp>
@ -30,7 +38,7 @@ 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;
{
@ -54,24 +62,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 +76,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 +159,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 +196,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 +227,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 +283,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,7 +310,7 @@ 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();
@ -352,7 +345,7 @@ 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();
@ -383,7 +376,7 @@ void EventFactory::delay() {
}
}
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
@ -417,35 +410,42 @@ EventFactory& EventFactory::getInstance() {
return ef;
}
Status EventFactory::registerEventPublisher(const EventPublisherRef event_pub) {
Status EventFactory::registerEventPublisher(const EventPublisherRef& pub) {
auto& ef = EventFactory::getInstance();
auto type_id = event_pub->type();
auto type_id = pub->type();
if (ef.getEventPublisher(type_id) != nullptr) {
// This is a duplicate type id?
return Status(1, "Duplicate Event Type");
}
if (!event_pub->setUp().ok()) {
if (!pub->setUp().ok()) {
// Only add the publisher if setUp was successful.
return Status(1, "SetUp failed.");
}
ef.event_pubs_[type_id] = event_pub;
ef.event_pubs_[type_id] = pub;
return Status(0, "OK");
}
Status EventFactory::registerEventSubscriber(
const EventSubscriberRef event_module) {
const EventSubscriberRef& event_module) {
auto& ef = EventFactory::getInstance();
// Let the module initialize any Subscriptions.
event_module->init();
ef.event_modules_.push_back(event_module);
ef.event_subs_[event_module->name()] = event_module;
return Status(0, "OK");
}
Status EventFactory::addSubscription(EventPublisherID type_id,
const SubscriptionRef subscription) {
Status EventFactory::addSubscription(EventPublisherID& type_id,
const SubscriptionContextRef& mc,
EventCallback cb) {
auto subscription = Subscription::create(mc, cb);
return EventFactory::addSubscription(type_id, subscription);
}
Status EventFactory::addSubscription(EventPublisherID& type_id,
const SubscriptionRef& subscription) {
auto event_pub = EventFactory::getInstance().getEventPublisher(type_id);
if (event_pub == nullptr) {
// Cannot create a Subscription for a missing type_id.
@ -458,14 +458,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 +467,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 +476,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(EventPublisherID type_id) {
Status EventFactory::deregisterEventPublisher(const EventPublisherRef& pub) {
return EventFactory::deregisterEventPublisher(pub->type());
}
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()) {

View 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>
@ -8,12 +16,10 @@
#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;
}

View 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>
@ -7,71 +19,109 @@
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;
};
class FakeBasicEventPublisher : public EventPublisher {
DECLARE_EVENTPUBLISHER(FakeBasicEventPublisher,
SubscriptionContext,
EventContext);
// 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 AnotherFakeEventPublisher
: public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
DECLARE_PUBLISHER("AnotherFakePublisher");
};
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) {
Status status;
// 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;
}

View 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.
*
*/
#pragma once
#include <osquery/events.h>

View 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>
@ -97,7 +105,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 +116,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 +140,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;

View 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.

View 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>
@ -163,22 +171,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);
@ -186,10 +194,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);
@ -197,9 +212,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_;
@ -209,17 +224,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();
@ -228,20 +244,21 @@ 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();
auto sc = sub->GetSubscription(kRealTestPath, 0);
sub->subscribe(&TestINotifyEventSubscriber::Callback, sc);
SubscriptionAction(
kRealTestPath, 0, TestINotifyEventSubscriber::EventCallback);
TriggerEvent(kRealTestPath);
TestINotifyEventSubscriber::WaitForEvents(kMaxEventLatency, 4);
sub->WaitForEvents(kMaxEventLatency, 4);
// Make sure the inotify action was expected.
EXPECT_EQ(TestINotifyEventSubscriber::actions().size(), 4);
EXPECT_EQ(TestINotifyEventSubscriber::actions()[0], "UPDATED");
EXPECT_EQ(TestINotifyEventSubscriber::actions()[1], "OPENED");
EXPECT_EQ(TestINotifyEventSubscriber::actions()[2], "UPDATED");
EXPECT_EQ(TestINotifyEventSubscriber::actions()[3], "UPDATED");
EXPECT_EQ(sub->actions().size(), 4);
EXPECT_EQ(sub->actions()[0], "UPDATED");
EXPECT_EQ(sub->actions()[1], "OPENED");
EXPECT_EQ(sub->actions()[2], "UPDATED");
EXPECT_EQ(sub->actions()[3], "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();
}

View 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;

View 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);
};
}

View 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>

View File

@ -1,6 +1,12 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <osquery/filesystem.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 <sstream>
@ -11,34 +17,33 @@
#import <Foundation/Foundation.h>
using osquery::Status;
#include <osquery/filesystem.h>
namespace pt = boost::property_tree;
namespace osquery {
NSMutableArray* filterArray(id dataStructure);
NSMutableDictionary* filterDictionary(id dataStructure);
NSMutableDictionary* filterDictionary(id dataStructure) {
@autoreleasepool {
NSMutableDictionary* result = [NSMutableDictionary new];
for (id key in [dataStructure allKeys]) {
id klass = [[dataStructure objectForKey:key] class];
NSString* className = NSStringFromClass(klass);
if ([className isEqualToString:@"__NSArrayI"] ||
[className isEqualToString:@"__NSArrayM"] ||
[className isEqualToString:@"__NSCFArray"]) {
id value = [dataStructure objectForKey:key];
if ([value isKindOfClass:[NSArray class]]) {
[result setObject:filterArray([dataStructure objectForKey:key])
forKey:key];
} else if ([className isEqualToString:@"__NSCFDictionary"]) {
} else if ([value isKindOfClass:[NSDictionary class]]) {
[result setObject:filterDictionary([dataStructure objectForKey:key])
forKey:key];
} else if ([className isEqualToString:@"__NSCFData"]) {
id data = [dataStructure objectForKey:key];
NSString* dataString =
[[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSASCIIStringEncoding];
} else if ([value isKindOfClass:[NSData class]]) {
NSString* dataString = [value base64EncodedStringWithOptions:0];
[result setObject:dataString forKey:key];
} else if ([value isKindOfClass:[NSDate class]]) {
NSNumber* seconds =
[[NSNumber alloc] initWithDouble:[value timeIntervalSince1970]];
[result setObject:seconds forKey:key];
} else {
[result setObject:[dataStructure objectForKey:key] forKey:key];
}
@ -51,20 +56,17 @@ NSMutableArray* filterArray(id dataStructure) {
@autoreleasepool {
NSMutableArray* result = [NSMutableArray new];
for (id value in dataStructure) {
NSString* className = NSStringFromClass([value class]);
if ([className isEqualToString:@"__NSCFDictionary"]) {
if ([value isKindOfClass:[NSDictionary class]]) {
[result addObject:filterDictionary(value)];
} else if ([className isEqualToString:@"__NSArrayI"] ||
[className isEqualToString:@"__NSArrayM"] ||
[className isEqualToString:@"__NSCFArray"]) {
} else if ([value isKindOfClass:[NSArray class]]) {
[result addObject:filterArray(value)];
} else if ([className isEqualToString:@"__NSCFData"]) {
id data = [dataStructure objectForKey:value];
NSString* dataString =
[[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSASCIIStringEncoding];
} else if ([value isKindOfClass:[NSData class]]) {
NSString* dataString = [value base64EncodedStringWithOptions:0];
[result addObject:dataString];
} else if ([value isKindOfClass:[NSDate class]]) {
NSNumber* seconds =
[[NSNumber alloc] initWithDouble:[value timeIntervalSince1970]];
[result addObject:seconds];
} else {
[result addObject:value];
}
@ -73,8 +75,16 @@ NSMutableArray* filterArray(id dataStructure) {
}
}
NSMutableDictionary* filterPlist(NSMutableDictionary* plist) {
return filterDictionary(plist);
NSMutableDictionary* filterPlist(NSData* plist) {
@autoreleasepool {
if ([plist isKindOfClass:[NSDictionary class]]) {
return filterDictionary((NSMutableDictionary*)plist);
} else {
NSMutableDictionary* result = [NSMutableDictionary new];
[result setObject:filterArray((NSMutableArray*)plist) forKey:@"root"];
return result;
}
}
}
Status parsePlistContent(const std::string& fileContent, pt::ptree& tree) {
@ -91,15 +101,15 @@ Status parsePlistContent(const std::string& fileContent, pt::ptree& tree) {
[NSData dataWithBytes:fileContent.c_str() length:fileContent.size()];
NSError* error = nil;
NSMutableDictionary* plist;
NSPropertyListFormat plistFormat;
id plistData = [NSPropertyListSerialization
propertyListWithData:plistContent
options:NSPropertyListImmutable
format:&plistFormat
error:&error];
NSMutableDictionary* plist = (NSMutableDictionary*)plistData;
if (plist == nil) {
if (plistData == nil) {
std::string errorMessage([[error localizedFailureReason] UTF8String]);
LOG(ERROR) << errorMessage;
statusCode = 1;
@ -123,7 +133,7 @@ Status parsePlistContent(const std::string& fileContent, pt::ptree& tree) {
}
try {
plist = filterPlist(plist);
plist = filterPlist(plistData);
} catch (const std::exception& e) {
LOG(ERROR)
<< "An exception occurred while filtering the plist: " << e.what();

View 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 <glog/logging.h>
#include <gtest/gtest.h>
@ -7,7 +15,7 @@
#include <osquery/filesystem.h>
#include <osquery/flags.h>
#include "osquery/core/darwin/test_util.h"
#include "osquery/core/test_util.h"
using namespace osquery::core;
namespace pt = boost::property_tree;
@ -26,10 +34,13 @@ TEST_F(PlistBenchmark, bench_parse_plist_content) {
LOG(ERROR) << "Performing " << FLAGS_iterations << " iterations";
int time = getUnixTime();
for (int i = 0; i < FLAGS_iterations; ++i) {
std::string content = getPlistContent();
std::string content;
readFile(kTestDataPath + "test.plist", content);
pt::ptree tree;
auto s = parsePlistContent(content, tree);
EXPECT_TRUE(s.ok());
EXPECT_EQ(s.toString(), "OK");
EXPECT_EQ(tree.get<bool>("Disabled"), true);
EXPECT_THROW(tree.get<bool>("foobar"), pt::ptree_bad_path);

View 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/filesystem.h>
@ -7,7 +15,8 @@
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "osquery/core/darwin/test_util.h"
#include "osquery/core/conversions.h"
#include "osquery/core/test_util.h"
using namespace osquery::core;
namespace fs = boost::filesystem;
@ -19,23 +28,22 @@ namespace osquery {
class PlistTests : public testing::Test {};
TEST_F(PlistTests, test_parse_plist) {
std::string path = "/System/Library/LaunchDaemons/com.apple.kextd.plist";
boost::property_tree::ptree tree;
auto s = parsePlist(path, tree);
EXPECT_TRUE(s.ok());
EXPECT_EQ(s.toString(), "OK");
}
TEST_F(PlistTests, test_parse_plist_content) {
std::string content = getPlistContent();
// Isolate plist parsing errors to the plist parser, instead of file reader.
std::string content;
readFile(kTestDataPath + "test.plist", content);
pt::ptree tree;
auto s = parsePlistContent(content, tree);
EXPECT_TRUE(s.ok());
EXPECT_EQ(s.toString(), "OK");
// Check the specifics of the PLIST.
EXPECT_EQ(tree.get<bool>("Disabled"), true);
EXPECT_THROW(tree.get<bool>("foobar"), pt::ptree_bad_path);
EXPECT_EQ(tree.get<std::string>("Label"), "com.apple.FileSyncAgent.sshd");
std::vector<std::string> program_arguments = {
"/System/Library/CoreServices/FileSyncAgent.app/Contents/Resources/"
"FileSyncAgent_sshd-keygen-wrapper",
@ -52,10 +60,28 @@ TEST_F(PlistTests, test_parse_plist_content) {
EXPECT_EQ(program_arguments_parsed, program_arguments);
}
TEST_F(PlistTests, test_parse_plist_from_file) {
// Now read the plist from a file and parse.
boost::property_tree::ptree tree;
auto s = parsePlist(kTestDataPath + "test.plist", tree);
EXPECT_TRUE(s.ok());
EXPECT_EQ(s.toString(), "OK");
}
TEST_F(PlistTests, test_parse_plist_array) {
// Now read the plist from a file and parse.
boost::property_tree::ptree tree;
auto s = parsePlist(kTestDataPath + "test_array.plist", tree);
EXPECT_TRUE(s.ok());
EXPECT_EQ(s.toString(), "OK");
}
TEST_F(PlistTests, test_parse_plist_content_with_blobs) {
pt::ptree tree;
fs::path bin_path(argv0);
auto s = parsePlist((bin_path.parent_path() /
"../../../../tools/tests/test_binary.plist").string(),
tree);
@ -67,7 +93,8 @@ TEST_F(PlistTests, test_parse_plist_content_with_blobs) {
auto first_element =
tree.get_child("SessionItems.CustomListItems").begin()->second;
EXPECT_EQ(first_element.get<std::string>("Name"), "Flux");
std::string alias = first_element.get<std::string>("Alias");
std::string alias = base64Decode(first_element.get<std::string>("Alias"));
// Verify we parsed the binary blob correctly
EXPECT_NE(alias.find("Applications/Flux.app"), std::string::npos);
}

View 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>

View 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/filesystem.h>

View 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>

View 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 <thread>

View 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>
#include <glog/logging.h>

View 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 <thread>

View 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 <mutex>

View 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 <boost/thread.hpp>
#include <glog/logging.h>

View 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>

View 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>

View 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>

View 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>

View 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/registry.h>
#include <memory>

View 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 {

View 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 <climits>
#include <ctime>

View 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 <gtest/gtest.h>
#include <osquery/scheduler.h>

View File

@ -10,6 +10,7 @@ if(APPLE)
ADD_OSQUERY_LIBRARY(osquery_tables_darwin
events/darwin/passwd_changes.cpp
events/darwin/hardware_events.cpp
networking/darwin/interfaces.cpp
networking/darwin/listening_ports.cpp
networking/darwin/routes.cpp
@ -25,8 +26,10 @@ if(APPLE)
system/darwin/processes.cpp
system/darwin/process_open_files.cpp
system/darwin/quarantine.cpp
system/darwin/pci_devices.cpp
system/darwin/usb_devices.cpp
system/darwin/startup_items.cpp
system/darwin/xprotect.cpp
)
ADD_OSQUERY_LINK("-framework Foundation")
@ -56,6 +59,7 @@ else()
system/linux/groups.cpp
system/linux/mounts.cpp
system/linux/pci_devices.cpp
system/linux/usb_devices.cpp
system/linux/block_devices.cpp
)
@ -77,10 +81,12 @@ FILE(GLOB table_sources
ADD_OSQUERY_LIBRARY(osquery_tables
networking/utils.cpp
networking/etc_hosts.cpp
networking/etc_services.cpp
utility/time.cpp
utility/crontab.cpp
utility/hash.cpp
utility/file.cpp
utility/osquery.cpp
system/cpuid.cpp
system/last.cpp
system/shell_history.cpp

View File

@ -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/core.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
#include "osquery/events/darwin/iokit_hid.h"
namespace osquery {
namespace tables {
/**
* @brief Track IOKit HID events.
*/
class HardwareEventSubscriber : public EventSubscriber<IOKitHIDEventPublisher> {
DECLARE_SUBSCRIBER("HardwareEventSubscriber");
public:
void init();
Status Callback(const IOKitHIDEventContextRef& ec);
};
REGISTER_EVENTSUBSCRIBER(HardwareEventSubscriber);
void HardwareEventSubscriber::init() {
auto subscription = createSubscriptionContext();
// We don't want hardware value changes.
subscription->values = false;
subscribe(&HardwareEventSubscriber::Callback, subscription);
}
Status HardwareEventSubscriber::Callback(const IOKitHIDEventContextRef& ec) {
Row r;
r["action"] = ec->action;
// There is no path in IOKit, there's a location ID (may be useful).
r["path"] = ec->location;
// Type and driver are the name in IOKit
r["type"] = "hid";
r["driver"] = ec->transport;
r["model_id"] = ec->model_id;
r["model"] = ec->model;
r["vendor_id"] = ec->vendor_id;
r["vendor"] = ec->vendor;
r["serial"] = ec->serial; // Not always filled in.
r["revision"] = ec->version;
r["time"] = INTEGER(ec->time);
add(r, ec->time);
return Status(0, "OK");
}
}
}

View 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 <vector>
#include <string>
@ -21,9 +29,9 @@ const std::vector<std::string> kDarwinPasswdPaths = {
*
* This is mostly an example EventSubscriber implementation.
*/
class PasswdChangesEventSubscriber : public EventSubscriber {
DECLARE_EVENTSUBSCRIBER(PasswdChangesEventSubscriber, FSEventsEventPublisher);
DECLARE_CALLBACK(Callback, FSEventsEventContext);
class PasswdChangesEventSubscriber
: public EventSubscriber<FSEventsEventPublisher> {
DECLARE_SUBSCRIBER("PasswdChangesEventSubscriber");
public:
void init();
@ -36,7 +44,7 @@ class PasswdChangesEventSubscriber : public EventSubscriber {
*
* @return Was the callback successful.
*/
Status Callback(const FSEventsEventContextRef ec);
Status Callback(const FSEventsEventContextRef& ec);
};
/**
@ -50,14 +58,14 @@ REGISTER_EVENTSUBSCRIBER(PasswdChangesEventSubscriber);
void PasswdChangesEventSubscriber::init() {
for (const auto& path : kDarwinPasswdPaths) {
auto mc = FSEventsEventPublisher::createSubscriptionContext();
auto mc = createSubscriptionContext();
mc->path = path;
BIND_CALLBACK(Callback, mc);
subscribe(&PasswdChangesEventSubscriber::Callback, mc);
}
}
Status PasswdChangesEventSubscriber::Callback(
const FSEventsEventContextRef ec) {
const FSEventsEventContextRef& ec) {
Row r;
r["action"] = ec->action;
r["time"] = ec->time_string;

Some files were not shown because too many files have changed in this diff Show More