osquery-1/include/osquery/core.h

325 lines
9.7 KiB
C
Raw Normal View History

/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
2015-01-22 22:00:35 +00:00
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
2014-07-31 00:35:19 +00:00
#pragma once
2014-07-31 00:35:19 +00:00
#include <csignal>
#include <memory>
2016-03-11 08:30:20 +00:00
#include <mutex>
2014-07-31 00:35:19 +00:00
#include <string>
#include <vector>
#include <boost/filesystem/path.hpp>
2015-09-07 18:09:06 +00:00
2015-02-09 00:00:43 +00:00
#include <osquery/status.h>
2014-07-31 00:35:19 +00:00
2015-02-19 23:19:00 +00:00
// clang-format off
2014-11-13 06:33:27 +00:00
#ifndef STR
#define STR_OF(x) #x
#define STR(x) STR_OF(x)
#endif
2015-02-19 23:19:00 +00:00
#define STR_EX(x) x
#define CONCAT(x, y) STR(STR_EX(x)STR_EX(y))
2014-11-13 06:33:27 +00:00
2015-02-09 00:00:43 +00:00
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
#endif
2015-02-19 23:19:00 +00:00
// clang-format on
2015-02-09 00:00:43 +00:00
2015-04-17 00:40:19 +00:00
#ifndef __constructor__
2015-05-07 04:58:23 +00:00
#define __registry_constructor__ __attribute__((constructor(101)))
#define __plugin_constructor__ __attribute__((constructor(102)))
#else
#define __registry_constructor__ __attribute__((__constructor__(101)))
#define __plugin_constructor__ __attribute__((__constructor__(102)))
2015-04-17 00:40:19 +00:00
#endif
/// A configuration error is catastrophic and should exit the watcher.
#define EXIT_CATASTROPHIC 78
2015-03-03 23:03:14 +00:00
2014-08-15 07:25:30 +00:00
namespace osquery {
2014-07-31 00:35:19 +00:00
2016-02-05 03:12:48 +00:00
/// The version of osquery, includes the git revision if not tagged.
2014-09-15 19:23:07 +00:00
extern const std::string kVersion;
2016-02-05 03:12:48 +00:00
/// The SDK version removes any git revision hash (1.6.1-g0000 becomes 1.6.1).
2015-02-19 01:19:45 +00:00
extern const std::string kSDKVersion;
2016-02-05 03:12:48 +00:00
/// Identifies the build platform of either the core extension.
2015-05-27 23:50:57 +00:00
extern const std::string kSDKPlatform;
2014-11-13 06:33:27 +00:00
/// Use a macro for the sdk/platform literal, symbols available in lib.cpp.
2015-02-19 01:19:45 +00:00
#define OSQUERY_SDK_VERSION STR(OSQUERY_BUILD_SDK_VERSION)
2015-05-27 23:50:57 +00:00
#define OSQUERY_PLATFORM STR(OSQUERY_BUILD_PLATFORM)
2014-09-15 19:23:07 +00:00
2014-11-09 04:27:28 +00:00
/**
* @brief A helpful tool type to report when logging, print help, or debugging.
*/
2015-03-04 16:45:21 +00:00
enum ToolType {
OSQUERY_TOOL_UNKNOWN = 0,
OSQUERY_TOOL_SHELL,
OSQUERY_TOOL_DAEMON,
OSQUERY_TOOL_TEST,
2015-02-19 01:19:45 +00:00
OSQUERY_EXTENSION,
2014-11-09 04:27:28 +00:00
};
2016-03-11 08:30:20 +00:00
/// Helper alias for defining mutexes throughout the codebase.
using Mutex = std::mutex;
2016-02-05 03:12:48 +00:00
/// Helper alias for write locking a mutex.
2016-03-11 08:30:20 +00:00
using WriteLock = std::lock_guard<Mutex>;
/// Helper alias for read locking a mutex (do not support a ReadMutex).
// using ReadLock = std::shared_lock<std::shared_mutex>;
2015-09-07 18:09:06 +00:00
/// The osquery tool type for runtime decisions.
extern ToolType kToolType;
/**
* @brief The requested exit code.
*
* Use Initializer::shutdown to request shutdown in most cases.
* This will raise a signal to the main thread requesting the dispatcher to
* interrupt all services. There is a thread requesting a join of all services
* that will continue the shutdown process.
*/
extern volatile std::sig_atomic_t kExitCode;
2015-12-03 05:01:41 +00:00
class Initializer : private boost::noncopyable {
2015-03-03 23:03:14 +00:00
public:
/**
* @brief Sets up various aspects of osquery execution state.
*
2015-03-04 16:45:21 +00:00
* osquery needs a few things to happen as soon as the process begins
* executing. Initializer takes care of setting up the relevant parameters.
* Initializer should be called in an executable's `main()` function.
2015-03-03 23:03:14 +00:00
*
* @param argc the number of elements in argv
* @param argv the command-line arguments passed to `main()`
2015-03-04 16:45:21 +00:00
* @param tool the type of osquery main (daemon, shell, test, extension).
2015-03-03 23:03:14 +00:00
*/
2015-03-19 03:47:35 +00:00
Initializer(int& argc, char**& argv, ToolType tool = OSQUERY_TOOL_TEST);
2015-03-03 23:03:14 +00:00
/**
* @brief Sets up the process as an osquery daemon.
*
* A daemon has additional constraints, it can use a process mutex, check
2015-03-03 23:03:14 +00:00
* for sane/non-default configurations, etc.
*/
2016-02-05 03:12:48 +00:00
void initDaemon() const;
2015-03-03 23:03:14 +00:00
/**
* @brief Daemon tools may want to continually spawn worker processes
* and monitor their utilization.
*
* A daemon may call initWorkerWatcher to begin watching child daemon
* processes until it-itself is unscheduled. The basic guarantee is that only
2015-03-03 23:03:14 +00:00
* workers will return from the function.
*
* The worker-watcher will implement performance bounds on CPU utilization
* and memory, as well as check for zombie/defunct workers and respawn them
* if appropriate. The appropriateness is determined from heuristics around
* how the worker exited. Various exit states and velocities may cause the
2015-03-03 23:03:14 +00:00
* watcher to resign.
*
* @param name The name of the worker process.
*/
void initWorkerWatcher(const std::string& name = "") const;
2015-03-03 23:03:14 +00:00
/// Assume initialization finished, start work.
2016-02-05 03:12:48 +00:00
void start() const;
/**
* @brief Forcefully request the application stop.
*
* Since all osquery tools may implement various 'dispatched' services in the
* form of event handler threads or thrift service and client pools, a stop
* request should behave nicely and request these services stop.
*
* Use shutdown whenever you would normally call ::exit.
*
* @param retcode the requested return code for the process.
*/
static void requestShutdown(int retcode = EXIT_SUCCESS);
/// Exit immediately without requesting the dispatcher to stop.
static void shutdown(int retcode = EXIT_SUCCESS);
/**
* @brief Cleanly wait for all services and components to shutdown.
*
* Enter a join of all services followed by a sync wait for event loops.
* If the main thread is out of actions it can call ::waitForShutdown.
*/
static void waitForShutdown();
public:
/**
* @brief Check if a process is an osquery worker.
*
* By default an osqueryd process will fork/exec then set an environment
* variable: `OSQUERY_WORKER` while continually monitoring child I/O.
* The environment variable causes subsequent child processes to skip several
* initialization steps and jump into extension handling, registry setup,
* config/logger discovery and then the event publisher and scheduler.
*/
static bool isWorker();
2015-03-03 23:03:14 +00:00
private:
/// Initialize this process as an osquery daemon worker.
2016-02-05 03:12:48 +00:00
void initWorker(const std::string& name) const;
/// Initialize the osquery watcher, optionally spawn a worker.
2016-02-05 03:12:48 +00:00
void initWatcher() const;
/// Set and wait for an active plugin optionally broadcasted.
2016-02-05 03:12:48 +00:00
void initActivePlugin(const std::string& type, const std::string& name) const;
2015-03-03 23:03:14 +00:00
private:
/// A saved, mutable, reference to the process's argc.
2015-12-03 05:01:41 +00:00
int* argc_{nullptr};
/// A saved, mutable, reference to the process's argv.
2015-12-03 05:01:41 +00:00
char*** argv_{nullptr};
/// The deduced tool type, determined by initializer construction.
2015-12-03 05:01:41 +00:00
ToolType tool_;
/// The deduced program name determined by executing path.
2015-03-03 23:03:14 +00:00
std::string binary_;
};
/**
* @brief Getter for a host's current hostname
2014-09-15 19:23:07 +00:00
*
* @return a string representing the host's current hostname
2014-09-15 19:23:07 +00:00
*/
std::string getHostname();
2015-08-25 23:26:57 +00:00
/**
* @brief Getter for a host's uuid.
*
* @return ok on success and ident is set to the host's uuid, otherwise failure.
*/
Status getHostUUID(std::string& ident);
/**
* @brief generate a uuid to uniquely identify this machine
*
* @return uuid string to identify this machine
*/
std::string generateHostUUID();
/**
* @brief Get a configured UUID/name that uniquely identify this machine
*
* @return string to identify this machine
*/
std::string getHostIdentifier();
/**
* @brief Getter for the current time, in a human-readable format.
2014-09-15 19:23:07 +00:00
*
* @return the current date/time in the format: "Wed Sep 21 10:27:52 2011"
2014-09-15 19:23:07 +00:00
*/
std::string getAsciiTime();
/**
* @brief Getter for the current UNIX time.
2014-09-15 19:23:07 +00:00
*
* @return an int representing the amount of seconds since the UNIX epoch
2014-09-15 19:23:07 +00:00
*/
size_t getUnixTime();
2014-11-18 02:42:36 +00:00
/**
* @brief Create a pid file
*
* @return A status object indicating the success or failure of the operation
*/
Status createPidFile();
class DropPrivileges;
typedef std::shared_ptr<DropPrivileges> DropPrivilegesRef;
class DropPrivileges : private boost::noncopyable {
public:
/// Make call sites use 'dropTo' booleans to improve the UI.
static DropPrivilegesRef get() {
DropPrivilegesRef handle = DropPrivilegesRef(new DropPrivileges());
return handle;
}
/**
* @brief Attempt to drop privileges to that of the parent of a given path.
*
* This will return false if privileges could not be dropped or there was
* an previous, and still active, request for dropped privileges.
*
* @return success if privileges were dropped, otherwise false.
*/
bool dropToParent(const boost::filesystem::path& path);
/// See DropPrivileges::dropToParent but explicitly set the UID and GID.
bool dropTo(uid_t uid, gid_t gid);
/// Check if effective privileges do not match real.
bool dropped() { return (getuid() != geteuid() || getgid() != getegid()); }
/**
* @brief The privilege/permissions dropper deconstructor will restore
* effective permissions.
*
* There should only be a single drop of privilege/permission active.
*/
virtual ~DropPrivileges();
private:
DropPrivileges() : dropped_(false), to_user_(0), to_group_(0) {}
/// Restore groups if dropping consecutively.
void restoreGroups();
private:
/// Boolean to track if this instance needs to restore privileges.
bool dropped_;
/// The user this instance dropped privileges to.
uid_t to_user_;
/// The group this instance dropped privileges to.
gid_t to_group_;
2015-11-05 18:10:11 +00:00
/// If this was a filesystem-prompted privilege drop.
bool fs_drop_{false};
/// Store times for restoration if requested.
struct timespec atime;
struct timespec mtime;
2015-11-05 18:10:11 +00:00
/**
* @brief If dropping explicitly to a user and group also drop groups.
*
* Original process groups before explicitly dropping privileges.
* On restore, if there are any groups in this list, they will be added
* to the processes group list.
*/
gid_t* original_groups_{nullptr};
2015-11-05 18:10:11 +00:00
/// The size of the original groups to backup when restoring privileges.
size_t group_size_{0};
private:
FRIEND_TEST(PermissionsTests, test_explicit_drop);
FRIEND_TEST(PermissionsTests, test_path_drop);
FRIEND_TEST(PermissionsTests, test_nobody_drop);
};
2014-11-17 21:47:44 +00:00
}