void genBrowserPlugin(const std::string& uid, const std::string& path, QueryData& results, bool is_disabled = false) { Row r; pt::ptree tree; r["uid"] = uid; auto info_path = path + "/Contents/Info.plist"; // Ensure that what we're processing is actually a plug-in. if (!pathExists(info_path)) { return; } if (osquery::parsePlist(info_path, tree).ok()) { // Plugin did not include an Info.plist, or it was invalid for (const auto& it : kBrowserPluginKeys) { r[it.second] = tree.get(it.first, ""); // Convert bool-types to an integer. jsonBoolAsInt(r[it.second]); } } if (r.count("native") == 0 || r.at("native").size() == 0) { // The default case for native execution is false. r["native"] = "0"; } r["path"] = path; r["disabled"] = (is_disabled) ? "1" : "0"; results.push_back(std::move(r)); }
std::string generateRow(const Row& r, const std::map<std::string, size_t>& lengths, const std::vector<std::string>& order) { std::string out; for (const auto& column : order) { size_t size = 0; // Print a terminator for the previous value or lhs, followed by spaces. out += kToken + ' '; if (r.count(column) == 0 || lengths.count(column) == 0) { size = column.size() - utf8StringSize(FLAGS_nullvalue); out += FLAGS_nullvalue; } else { int buffer_size = static_cast<int>(lengths.at(column) - utf8StringSize(r.at(column))); if (buffer_size >= 0) { size = static_cast<size_t>(buffer_size); out += r.at(column); } } out += std::string(size + 1, ' '); } if (out.size() > 0) { // Only append if a row was added. out += kToken + "\n"; } return out; }
void EventSubscriberPlugin::expireCheck(bool cleanup) { auto data_key = "data." + dbNamespace(); auto eid_key = "eid." + dbNamespace(); // Min key will be the last surviving key. size_t min_key = 0; { auto limit = getEventsMax(); std::vector<std::string> keys; scanDatabaseKeys(kEvents, keys, data_key); if (keys.size() <= limit) { return; } // There is an overflow of events buffered for this subscriber. LOG(WARNING) << "Expiring events for subscriber: " << getName() << " (limit " << limit << ")"; VLOG(1) << "Subscriber events " << getName() << " exceeded limit " << limit << " by: " << keys.size() - limit; // Inspect the N-FLAGS_events_max -th event's value and expire before the // time within the content. std::string last_key; getDatabaseValue(kEvents, eid_key, last_key); // The EID is the next-index. // EID - events_max is the most last-recent event to keep. min_key = boost::lexical_cast<size_t>(last_key) - getEventsMax(); if (cleanup) { // Scan each of the keys in keys, if their ID portion is < min_key. // Nix them, this requires lots of conversions, use with care. for (const auto& key : keys) { if (std::stoul(key.substr(key.rfind('.') + 1)) < min_key) { deleteDatabaseValue(kEvents, key); } } } } // Convert the key index into a time using the content. // The last-recent event is fetched and the corresponding time is used as // the expiration time for the subscriber. std::string content; getDatabaseValue(kEvents, data_key + "." + std::to_string(min_key), content); // Decode the value into a row structure to extract the time. Row r; if (!deserializeRowJSON(content, r) || r.count("time") == 0) { return; } // The last time will become the implicit expiration time. size_t last_time = boost::lexical_cast<size_t>(r.at("time")); if (last_time > 0) { expire_time_ = last_time; } // Finally, attempt an index query to trigger expirations. // In this case the result set is not used. getIndexes(expire_time_, 0); }
void genBrowserPlugin(const std::string& uid, const std::string& path, QueryData& results) { Row r; pt::ptree tree; r["uid"] = uid; if (osquery::parsePlist(path + "/Contents/Info.plist", tree).ok()) { // Plugin did not include an Info.plist, or it was invalid for (const auto& it : kBrowserPluginKeys) { r[it.second] = tree.get(it.first, ""); // Convert bool-types to an integer. jsonBoolAsInt(r[it.second]); } } if (r.count("native") == 0 || r.at("native").size() == 0) { // The default case for native execution is false. r["native"] = "0"; } r["path"] = path; results.push_back(std::move(r)); }
TEST_F(AslTests, test_read_asl_row) { aslmsg row = asl_new(ASL_TYPE_MSG); ASSERT_EQ(0, asl_set(row, "Sender", "foo")); ASSERT_EQ(0, asl_set(row, "Level", "1")); ASSERT_EQ(0, asl_set(row, "Message", "bar")); ASSERT_EQ(0, asl_set(row, "Bang", "bang_val")); Row r; readAslRow(row, r); ASSERT_EQ((size_t)4, r.size()); ASSERT_EQ("foo", r["sender"]); ASSERT_EQ("1", r["level"]); ASSERT_EQ("bar", r["message"]); ASSERT_EQ((size_t)0, r.count("bang")); ASSERT_EQ("{\"Bang\":\"bang_val\"}\n", r["extra"]); asl_release(row); }
void EventSubscriberPlugin::expireCheck() { auto db = DBHandle::getInstance(); auto data_key = "data." + dbNamespace(); auto eid_key = "eid." + dbNamespace(); std::vector<std::string> keys; db->ScanPrefix(kEvents, keys, data_key); if (keys.size() <= FLAGS_events_max) { return; } // There is an overflow of events buffered for this subscriber. LOG(WARNING) << "Expiring events for subscriber: " << getName() << " limit (" << FLAGS_events_max << ") exceeded: " << keys.size(); // Inspect the N-FLAGS_events_max -th event's value and expire before the // time within the content. std::string last_key; db->Get(kEvents, eid_key, last_key); // The EID is the next-index. size_t max_key = boost::lexical_cast<size_t>(last_key) - FLAGS_events_max - 1; // Convert the key index into a time using the content. std::string content; db->Get(kEvents, data_key + "." + std::to_string(max_key), content); // Decode the value into a row structure to extract the time. Row r; if (!deserializeRowJSON(content, r) || r.count("time") == 0) { return; } // The last time will become the implicit expiration time. size_t last_time = boost::lexical_cast<size_t>(r.at("time")); if (last_time > 0) { expire_time_ = last_time; } // Finally, attempt an index query to trigger expirations. // In this case the result set is not used. getIndexes(expire_time_ - 1, -1); }
int queryDataCallback(void* argument, int argc, char* argv[], char* column[]) { if (argument == nullptr) { VLOG(1) << "Query execution failed: received a bad callback argument"; return SQLITE_MISUSE; } auto qData = static_cast<QueryData*>(argument); Row r; for (int i = 0; i < argc; i++) { if (column[i] != nullptr) { if (r.count(column[i])) { // Found a column name collision in the result. VLOG(1) << "Detected overloaded column name " << column[i] << " in query result consider using aliases"; } r[column[i]] = (argv[i] != nullptr) ? argv[i] : FLAGS_nullvalue; } } (*qData).push_back(std::move(r)); return 0; }
QueryData genDrivers(QueryContext& context) { QueryData results; auto devInfoset = setupDevInfoSet(); if (devInfoset == nullptr) { win32LogWARNING("Error getting device handle"); return results; } std::vector<SP_DEVINFO_DATA> devices; auto ret = getDeviceList(devInfoset, devices); if (!ret.ok()) { win32LogWARNING(ret.getMessage(), ret.getCode()); return results; } for (auto& device : devices) { char devId[MAX_DEVICE_ID_LEN] = {0}; if (CM_Get_Device_ID(device.DevInst, devId, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) { win32LogWARNING("Failed to get device ID"); return QueryData(); } SP_DRVINFO_DATA drvInfo = {0}; SP_DRVINFO_DETAIL_DATA drvInfoDetail = {0}; ret = getDeviceDriverInfo(devInfoset, device, drvInfo, drvInfoDetail); Row r; r["device_id"] = devId; r["inf"] = drvInfoDetail.InfFileName; r["provider"] = drvInfo.ProviderName; r["manufacturer"] = drvInfo.MfgName; r["date"] = std::to_string(osquery::filetimeToUnixtime(drvInfo.DriverDate)); r["description"] = drvInfo.Description; ULARGE_INTEGER version; version.QuadPart = drvInfo.DriverVersion; r["version"] = std::to_string(HIWORD(version.HighPart)) + "." + std::to_string(HIWORD(version.LowPart)) + "." + std::to_string(LOWORD(version.HighPart)) + "." + std::to_string(LOWORD(version.LowPart)); for (const auto& elem : kAdditionalDeviceProps) { std::string val; ret = getDeviceProperty(devInfoset, device, elem.second, val); r[elem.first] = std::move(val); } if (r.count("driver_key") > 0) { if (!r.at("driver_key").empty()) { r["driver_key"].insert(0, kDriverKeyPath); } } if (r.count("service") > 0) { if (!r.at("service").empty()) { r["service_key"] = kServiceKeyPath + r["service"]; r["image"] = getDriverImagePath(r["service_key"]); } } results.push_back(r); } return results; }
QueryData genKernelInfo(QueryContext& context) { QueryData results; mach_port_t master_port; auto kr = IOMasterPort(bootstrap_port, &master_port); if (kr != KERN_SUCCESS) { VLOG(1) << "Could not get the IOMaster port"; return {}; } // NVRAM registry entry is :/options. auto chosen = IORegistryEntryFromPath(master_port, kIODTChosenPath_); if (chosen == 0) { VLOG(1) << "Could not get IOKit boot device"; return {}; } // Parse the boot arguments, usually none. CFMutableDictionaryRef properties; kr = IORegistryEntryCreateCFProperties( chosen, &properties, kCFAllocatorDefault, 0); IOObjectRelease(chosen); if (kr != KERN_SUCCESS) { VLOG(1) << "Could not get IOKit boot device properties"; return {}; } Row r; CFTypeRef property; if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-args"), &property)) { r["arguments"] = stringFromCFData((CFDataRef)property); } if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-device-path"), &property)) { r["device"] = getCanonicalEfiDevicePath((CFDataRef)property); } if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-file"), &property)) { r["path"] = stringFromCFData((CFDataRef)property); boost::trim(r["path"]); } // No longer need chosen properties. CFRelease(properties); // The kernel version, signature, and build information is stored in Root. auto root = IORegistryGetRootEntry(master_port); if (root != 0) { property = (CFDataRef)IORegistryEntryCreateCFProperty( root, CFSTR(kIOKitBuildVersionKey), kCFAllocatorDefault, 0); if (property != nullptr) { // The version is in the form: // Darwin Kernel Version VERSION: DATE; root:BUILD/TAG auto signature = stringFromCFString((CFStringRef)property); CFRelease(property); r["version"] = signature.substr(22, signature.find(":") - 22); } } // With the path and device, try to locate the on-disk kernel if (r.count("path") > 0) { // This does not use the device path, potential invalidation. r["md5"] = hashFromFile(HASH_TYPE_MD5, "/" + r["path"]); } results.push_back(r); return results; }