// Copyright 2004-present Facebook. All Rights Reserved. #pragma once #include #include #include #include #include #include "osquery/status.h" #include "osquery/events.h" namespace osquery { extern std::map kMaskActions; struct FSEventsMonitorContext : public MonitorContext { /// Monitor the following filesystem path. std::string path; /// Limit the FSEvents actions to the monitored mask (if not 0). FSEventStreamEventFlags mask; void requireAction(std::string action) { for (const auto& bit : kMaskActions) { if (action == bit.second) { mask = mask & bit.first; } } } FSEventsMonitorContext() : mask(0) {} }; struct FSEventsEventContext : public EventContext { ConstFSEventStreamRef fsevent_stream; FSEventStreamEventFlags fsevent_flags; FSEventStreamEventId fsevent_id; std::string path; std::string action; FSEventsEventContext() : fsevent_flags(0), fsevent_id(0) {} }; typedef std::shared_ptr FSEventsEventContextRef; typedef std::shared_ptr FSEventsMonitorContextRef; /** * @brief An osquery EventPublisher for the Apple FSEvents notification API. * * This exposes a lightweight filesystem eventing type by wrapping Apple's * preferred implementation of FSEvents handling. * */ class FSEventsEventPublisher : public EventPublisher { DECLARE_EVENTTYPE(FSEventsEventPublisher, FSEventsMonitorContext, FSEventsEventContext) public: void configure(); void tearDown(); // Entrypoint to the run loop Status run(); 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: FSEventsEventPublisher() : EventPublisher(), stream_(nullptr), run_loop_(nullptr) {} bool shouldFire(const FSEventsMonitorContextRef mc, const FSEventsEventContextRef ec); 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(); // Count the number of monitored paths. size_t numMonitoredPaths(); private: FSEventStreamRef stream_; bool stream_started_; std::set paths_; private: CFRunLoopRef run_loop_; private: friend class FSEventsTests; FRIEND_TEST(FSEventsTests, test_register_event_pub); FRIEND_TEST(FSEventsTests, test_fsevents_add_monitor_missing_path); FRIEND_TEST(FSEventsTests, test_fsevents_add_monitor_success); FRIEND_TEST(FSEventsTests, test_fsevents_run); FRIEND_TEST(FSEventsTests, test_fsevents_fire_event); FRIEND_TEST(FSEventsTests, test_fsevents_event_action); }; }