2014-12-18 18:50:47 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-05-12 06:31:13 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2014-12-18 18:50:47 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <boost/make_shared.hpp>
|
|
|
|
|
|
|
|
#include <CoreServices/CoreServices.h>
|
|
|
|
|
2014-12-03 23:14:02 +00:00
|
|
|
#include <osquery/events.h>
|
|
|
|
#include <osquery/status.h>
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
extern std::map<FSEventStreamEventFlags, std::string> kMaskActions;
|
|
|
|
|
2014-10-03 15:26:41 +00:00
|
|
|
struct FSEventsSubscriptionContext : public SubscriptionContext {
|
|
|
|
/// Subscription the following filesystem path.
|
2014-09-30 20:17:54 +00:00
|
|
|
std::string path;
|
2014-10-03 15:26:41 +00:00
|
|
|
/// Limit the FSEvents actions to the subscriptioned mask (if not 0).
|
2014-09-30 20:17:54 +00:00
|
|
|
FSEventStreamEventFlags mask;
|
2015-04-01 04:18:56 +00:00
|
|
|
// A no-op since FSEvent subscriptions are always recursive.
|
|
|
|
bool recursive;
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
void requireAction(std::string action) {
|
|
|
|
for (const auto& bit : kMaskActions) {
|
|
|
|
if (action == bit.second) {
|
|
|
|
mask = mask & bit.first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-12 02:50:35 +00:00
|
|
|
FSEventsSubscriptionContext() : mask(0), recursive(false) {}
|
2014-09-30 20:17:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct FSEventsEventContext : public EventContext {
|
|
|
|
ConstFSEventStreamRef fsevent_stream;
|
|
|
|
FSEventStreamEventFlags fsevent_flags;
|
2015-04-01 04:18:56 +00:00
|
|
|
FSEventStreamEventId transaction_id;
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
std::string path;
|
|
|
|
std::string action;
|
|
|
|
|
2015-04-01 04:18:56 +00:00
|
|
|
FSEventsEventContext() : fsevent_flags(0), transaction_id(0) {}
|
2014-09-30 20:17:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::shared_ptr<FSEventsEventContext> FSEventsEventContextRef;
|
2014-10-07 23:01:30 +00:00
|
|
|
typedef std::shared_ptr<FSEventsSubscriptionContext>
|
2014-10-28 00:37:36 +00:00
|
|
|
FSEventsSubscriptionContextRef;
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-10-03 15:14:36 +00:00
|
|
|
* @brief An osquery EventPublisher for the Apple FSEvents notification API.
|
2014-09-30 20:17:54 +00:00
|
|
|
*
|
|
|
|
* This exposes a lightweight filesystem eventing type by wrapping Apple's
|
|
|
|
* preferred implementation of FSEvents handling.
|
|
|
|
*
|
|
|
|
*/
|
2014-12-15 06:17:38 +00:00
|
|
|
class FSEventsEventPublisher
|
|
|
|
: public EventPublisher<FSEventsSubscriptionContext, FSEventsEventContext> {
|
2015-01-30 18:44:25 +00:00
|
|
|
DECLARE_PUBLISHER("fsevents");
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
void configure();
|
|
|
|
void tearDown();
|
|
|
|
|
|
|
|
// Entrypoint to the run loop
|
|
|
|
Status run();
|
2015-05-07 03:02:23 +00:00
|
|
|
// Callin for stopping the streams/run loop.
|
|
|
|
void end();
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// FSEvents registers a client callback instead of using a select/poll loop.
|
|
|
|
static void Callback(ConstFSEventStreamRef fsevent_stream,
|
|
|
|
void* callback_info,
|
|
|
|
size_t num_events,
|
|
|
|
void* event_paths,
|
|
|
|
const FSEventStreamEventFlags fsevent_flags[],
|
|
|
|
const FSEventStreamEventId fsevent_ids[]);
|
|
|
|
|
|
|
|
public:
|
2014-12-15 18:17:56 +00:00
|
|
|
FSEventsEventPublisher() : EventPublisher() {
|
|
|
|
stream_started_ = false;
|
|
|
|
stream_ = nullptr;
|
|
|
|
run_loop_ = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool shouldFire(const FSEventsSubscriptionContextRef& mc,
|
2015-02-11 03:18:56 +00:00
|
|
|
const FSEventsEventContextRef& ec) const;
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
// Restart the run loop.
|
|
|
|
void restart();
|
|
|
|
// Stop the stream and the run loop.
|
|
|
|
void stop();
|
|
|
|
// Cause the FSEvents to flush kernel-buffered events.
|
|
|
|
void flush(bool async = false);
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Check if the stream (and run loop) are running.
|
|
|
|
bool isStreamRunning();
|
2014-10-03 15:26:41 +00:00
|
|
|
// Count the number of subscriptioned paths.
|
|
|
|
size_t numSubscriptionedPaths();
|
2014-09-30 20:17:54 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
FSEventStreamRef stream_;
|
|
|
|
bool stream_started_;
|
|
|
|
std::set<std::string> paths_;
|
|
|
|
|
|
|
|
private:
|
|
|
|
CFRunLoopRef run_loop_;
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class FSEventsTests;
|
2014-10-03 15:14:36 +00:00
|
|
|
FRIEND_TEST(FSEventsTests, test_register_event_pub);
|
2014-10-03 15:26:41 +00:00
|
|
|
FRIEND_TEST(FSEventsTests, test_fsevents_add_subscription_missing_path);
|
|
|
|
FRIEND_TEST(FSEventsTests, test_fsevents_add_subscription_success);
|
2014-09-30 20:17:54 +00:00
|
|
|
FRIEND_TEST(FSEventsTests, test_fsevents_run);
|
|
|
|
FRIEND_TEST(FSEventsTests, test_fsevents_fire_event);
|
|
|
|
FRIEND_TEST(FSEventsTests, test_fsevents_event_action);
|
|
|
|
};
|
|
|
|
}
|