mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-06 17:45:22 +00:00
Merge branch 'master' of github.com:facebook/osquery into 520_pt_json_workaround
This commit is contained in:
commit
93cb303abc
1
TARGETS
1
TARGETS
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
@ -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
|
||||
|
||||
|
@ -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); \
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
53
osquery/core/conversions.cpp
Normal file
53
osquery/core/conversions.cpp
Normal 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();
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
61
osquery/core/darwin/conversions.cpp
Normal file
61
osquery/core/darwin/conversions.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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(), ¤t_value);
|
||||
return current_value;
|
||||
}
|
||||
|
||||
Status Flag::updateValue(const std::string& name, const std::string& value) {
|
||||
__GFLAGS_NAMESPACE::SetCommandLineOption(name.c_str(), value.c_str());
|
||||
return Status(0, "OK");
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -6,6 +6,7 @@ if(APPLE)
|
||||
|
||||
ADD_OSQUERY_LIBRARY(osquery_events_darwin
|
||||
darwin/fsevents.cpp
|
||||
darwin/iokit_hid.cpp
|
||||
darwin/scnetwork.cpp
|
||||
)
|
||||
elseif(FREEBSD)
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
195
osquery/events/darwin/iokit_hid.cpp
Normal file
195
osquery/events/darwin/iokit_hid.cpp
Normal 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;
|
||||
}
|
||||
}
|
149
osquery/events/darwin/iokit_hid.h
Normal file
149
osquery/events/darwin/iokit_hid.h
Normal 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_;
|
||||
};
|
||||
}
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
65
osquery/tables/events/darwin/hardware_events.cpp
Normal file
65
osquery/tables/events/darwin/hardware_events.cpp
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user