Status SyslogEventPublisher::run() { // This run function will be called by the event factory with ~100ms pause // (see InterruptableRunnable::pause()) between runs. In case something goes // weird and there is a huge amount of input, we limit how many logs we // take in per run to avoid pegging the CPU. for (size_t i = 0; i < kMaxLogsPerRun; ++i) { if (readStream_.rdbuf()->in_avail() == 0) { // If there is no pending data, we have flushed everything and can wait // until the next time EventFactory calls run(). This also allows the // thread to join when it is stopped by EventFactory. return Status(0, "OK"); } std::string line; std::getline(readStream_, line); auto ec = createEventContext(); Status status = populateEventContext(line, ec); if (status.ok()) { fire(ec); if (errorCount_ > 0) { --errorCount_; } } else { LOG(ERROR) << status.getMessage() << " in line: " << line; ++errorCount_; if (errorCount_ >= kErrorThreshold) { return Status(1, "Too many errors in syslog parsing."); } } } return Status(0, "OK"); }
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)); if (ec->location.size() > 0 || ec->model_id.size() > 0) { // Only emit results that contain an location or model_id. EventFactory::fire<IOKitHIDEventPublisher>(ec); } }
void SCNetworkEventPublisher::Callback(const SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { auto ec = createEventContext(); ec->subscription = *(SCNetworkSubscriptionContextRef*)info; ec->flags = flags; }
void IOKitEventPublisher::newEvent(const io_service_t& device, IOKitEventContext::Action action) { auto ec = createEventContext(); ec->action = action; { // The IORegistry name is not needed. io_name_t class_name = {0}; if (IOObjectGetClass(device, class_name) != kIOReturnSuccess) { return; } ec->type = std::string(class_name); } // Get the device details CFMutableDictionaryRef details; IORegistryEntryCreateCFProperties( device, &details, kCFAllocatorDefault, kNilOptions); if (ec->type == kIOUSBDeviceClassName_) { ec->path = getIOKitProperty(details, "USB Address") + ":"; ec->path += getIOKitProperty(details, "PortNum"); ec->model = getIOKitProperty(details, "USB Product Name"); ec->model_id = getIOKitProperty(details, "idProduct"); ec->vendor = getIOKitProperty(details, "USB Vendor Name"); ec->vendor_id = getIOKitProperty(details, "idVendor"); idToHex(ec->vendor_id); idToHex(ec->model_id); ec->serial = getIOKitProperty(details, "USB Serial Number"); if (ec->serial.size() == 0) { ec->serial = getIOKitProperty(details, "iSerialNumber"); } ec->version = ""; ec->driver = getIOKitProperty(details, "IOUserClientClass"); } else if (ec->type == kIOPCIDeviceClassName_) { auto compatible = getIOKitProperty(details, "compatible"); auto properties = IOKitPCIProperties(compatible); ec->model_id = properties.model_id; ec->vendor_id = properties.vendor_id; ec->driver = properties.driver; if (ec->driver.empty()) { ec->driver = getIOKitProperty(details, "IOName"); } ec->path = getIOKitProperty(details, "pcidebug"); ec->version = getIOKitProperty(details, "revision-id"); ec->model = getIOKitProperty(details, "model"); } else { // Get the name as the model. io_name_t name = {0}; IORegistryEntryGetName(device, name); if (name[0] != 0) { ec->model = std::string(name); } } CFRelease(details); fire(ec); }
void DiskArbitrationEventPublisher::DiskAppearedCallback(DADiskRef disk, void* context) { auto ec = createEventContext(); CFDictionaryRef disk_properties = DADiskCopyDescription(disk); CFTypeRef devicePathKey; if (!CFDictionaryGetValueIfPresent( disk_properties, kDADiskDescriptionDevicePathKey, &devicePathKey)) { CFRelease(disk_properties); return; } auto device_path = stringFromCFString((CFStringRef)devicePathKey); ec->device_path = device_path; auto entry = IORegistryEntryFromPath(kIOMasterPortDefault, device_path.c_str()); if (entry == MACH_PORT_NULL) { CFRelease(disk_properties); return; } auto protocol_properties = (CFDictionaryRef)IORegistryEntryCreateCFProperty( entry, CFSTR(kIOPropertyProtocolCharacteristicsKey_), kCFAllocatorDefault, kNilOptions); if (protocol_properties != nullptr) { CFDataRef path = (CFDataRef)CFDictionaryGetValue( protocol_properties, CFSTR(kVirtualInterfaceLocation_)); if (path != nullptr) { ec->path = stringFromCFData(path); // extract checksum once on the whole disk and not for every partition if (CFBooleanGetValue((CFBooleanRef)CFDictionaryGetValue( disk_properties, kDADiskDescriptionMediaWholeKey))) { ec->checksum = extractUdifChecksum(ec->path); } } else { // There was no interface location. ec->path = getProperty(kDADiskDescriptionDevicePathKey, disk_properties); } CFRelease(protocol_properties); } else { ec->path = ""; } if (ec->path.find("/SSD0@0") == std::string::npos) { // This is not an internal SSD. fire("add", ec, disk_properties); } CFRelease(disk_properties); IOObjectRelease(entry); }
void FSEventsEventPublisher::Callback( ConstFSEventStreamRef stream, void* callback_info, size_t num_events, void* event_paths, const FSEventStreamEventFlags fsevent_flags[], const FSEventStreamEventId fsevent_ids[]) { for (size_t i = 0; i < num_events; ++i) { auto ec = createEventContext(); ec->fsevent_stream = stream; ec->fsevent_flags = fsevent_flags[i]; ec->transaction_id = fsevent_ids[i]; ec->path = std::string(((char**)event_paths)[i]); if (ec->fsevent_flags & kFSEventStreamEventFlagMustScanSubDirs) { // The FSEvents thread coalesced events within and will report a root. TLOG << "FSEvents collision, root: " << ec->path; } if (ec->fsevent_flags & kFSEventStreamEventFlagRootChanged) { // Must rescan for the changed root. } if (ec->fsevent_flags & kFSEventStreamEventFlagUnmount) { // Should remove the watch on this path. } if (ec->fsevent_flags & kFSEventStreamEventFlagMount) { auto mc = std::make_shared<FSEventsSubscriptionContext>(); mc->path = ec->path + "/*"; auto subscription = Subscription::create("file_events", mc); auto status = EventFactory::addSubscription("fsevents", subscription); auto pub = EventFactory::getEventPublisher("fsevents"); pub->configure(); } // Record the string-version of the first matched mask bit. bool has_action = false; for (const auto& action : kMaskActions) { if (ec->fsevent_flags & action.first) { // Actions may be multiplexed. Fire and event for each. ec->action = action.second; EventFactory::fire<FSEventsEventPublisher>(ec); has_action = true; } } if (!has_action) { // If no action was matched for this path event, fire and unknown. ec->action = "UNKNOWN"; EventFactory::fire<FSEventsEventPublisher>(ec); } } }
INotifyEventContextRef INotifyEventPublisher::createEventContextFrom( struct inotify_event* event) { auto shared_event = std::make_shared<struct inotify_event>(*event); auto ec = createEventContext(); ec->event = shared_event; // Get the pathname the watch fired on. ec->path = descriptor_paths_[event->wd]; if (event->len > 1) { ec->path += event->name; } for (const auto& action : kMaskActions) { if (event->mask & action.first) { ec->action = action.second; break; } } return ec; }
UdevEventContextRef UdevEventPublisher::createEventContextFrom( struct udev_device* device) { auto ec = createEventContext(); ec->device = device; // Map the action string to the eventing enum. ec->action = UDEV_EVENT_ACTION_UNKNOWN; ec->action_string = std::string(udev_device_get_action(device)); if (ec->action_string == "add") { ec->action = UDEV_EVENT_ACTION_ADD; } else if (ec->action_string == "remove") { ec->action = UDEV_EVENT_ACTION_REMOVE; } else if (ec->action_string == "change") { ec->action = UDEV_EVENT_ACTION_CHANGE; } // Set the subscription-aware variables for the event. auto value = udev_device_get_subsystem(device); if (value != nullptr) { ec->subsystem = std::string(value); } value = udev_device_get_devnode(device); if (value != nullptr) { ec->devnode = std::string(value); } value = udev_device_get_devtype(device); if (value != nullptr) { ec->devtype = std::string(value); } value = udev_device_get_driver(device); if (value != nullptr) { ec->driver = std::string(value); } return ec; }
Status AuditEventPublisher::run() { if (!FLAGS_disable_audit && (count_ == 0 || count_++ % 10 == 0)) { // Request an update to the audit status. // This will also fill in the status on first run. audit_request_status(handle_); } // Reset the reply data. int result = 0; bool handle_reply = false; while (true) { handle_reply = false; // Request a reply in a non-blocking mode. // This allows the publisher's run loop to periodically request an audit // status update. These updates can check for other processes attempting to // gain control over the audit sink. // This non-blocking also allows faster receipt of multi-message events. result = audit_get_reply(handle_, &reply_, GET_REPLY_NONBLOCKING, 0); if (result > 0) { switch (reply_.type) { case NLMSG_NOOP: case NLMSG_DONE: case NLMSG_ERROR: // Not handled, request another reply. break; case AUDIT_LIST_RULES: // Build rules cache. handleListRules(); break; case AUDIT_GET: // Make a copy of the status reply and store as the most-recent. if (reply_.status != nullptr) { memcpy(&status_, reply_.status, sizeof(struct audit_status)); } break; case (AUDIT_GET + 1)...(AUDIT_LIST_RULES - 1): case (AUDIT_LIST_RULES + 1)... AUDIT_LAST_USER_MSG: // Not interested in handling meta-commands and actions. break; case AUDIT_DAEMON_START... AUDIT_DAEMON_CONFIG: // 1200 - 1203 case AUDIT_CONFIG_CHANGE: handleAuditConfigChange(reply_); break; case AUDIT_SYSCALL: // 1300 // A monitored syscall was issued, most likely part of a multi-record. handle_reply = true; break; case AUDIT_CWD: // 1307 case AUDIT_PATH: // 1302 case AUDIT_EXECVE: // // 1309 (execve arguments). handle_reply = true; case AUDIT_EOE: // 1320 (multi-record event). break; default: // All other cases, pass to reply. handle_reply = true; } } else { // Fall through to the run loop cool down. break; } // Replies are 'handled' as potential events for several audit types. if (handle_reply) { auto ec = createEventContext(); // Build the event context from the reply type and parse the message. if (handleAuditReply(reply_, ec)) { fire(ec); } } }
void DiskArbitrationEventPublisher::DiskDisappearedCallback(DADiskRef disk, void* context) { CFDictionaryRef disk_properties = DADiskCopyDescription(disk); fire("remove", createEventContext(), disk_properties); CFRelease(disk_properties); }