size_t restoreSplayedValue(const std::string& name, size_t interval) { // Attempt to restore a previously-calculated splay. std::string content; getDatabaseValue(kPersistentSettings, "interval." + name, content); if (!content.empty()) { // This query name existed before, check the last requested interval. auto details = osquery::split(content, ":"); if (details.size() == 2) { long last_interval, last_splay; if (safeStrtol(details[0], 10, last_interval) && safeStrtol(details[1], 10, last_splay)) { if (last_interval == static_cast<long>(interval) && last_splay > 0) { // This is a matching interval, use the previous splay. return static_cast<size_t>(last_splay); } } } } // If the splayed interval was not restored from the database. auto splay = splayValue(interval, FLAGS_schedule_splay_percent); content = std::to_string(interval) + ":" + std::to_string(splay); setDatabaseValue(kPersistentSettings, "interval." + name, content); return splay; }
bool DropPrivileges::dropTo(const std::string& user) { auto result = SQL::selectAllFrom("users", "username", EQUALS, user); if (result.size() == 0) { return false; } long uid = 0; long gid = 0; if (!safeStrtol(result[0].at("uid"), 10, uid) || !safeStrtol(result[0].at("gid"), 10, gid)) { return false; } return dropTo(static_cast<uid_t>(uid), static_cast<gid_t>(gid)); }
bool parseSockAddr(const std::string& saddr, AuditFields& r) { // The protocol is not included in the audit message. if (saddr[0] == '0' && saddr[1] == '2') { // IPv4 r["family"] = '2'; long result{0}; safeStrtol(saddr.substr(4, 4), 16, result); r["remote_port"] = INTEGER(result); r["remote_address"] = ip4FromSaddr(saddr, 8); } else if (saddr[0] == '0' && saddr[1] == 'A') { // IPv6 r["family"] = "11"; long result{0}; safeStrtol(saddr.substr(4, 4), 16, result); r["remote_port"] = INTEGER(result); std::string address; for (size_t i = 0; i < 8; ++i) { address += saddr.substr(16 + (i * 4), 4); if (i == 0 || i % 7 != 0) { address += ':'; } } boost::algorithm::to_lower(address); r["remote_address"] = std::move(address); } else if (saddr[0] == '0' && saddr[1] == '1' && saddr.size() > 6) { // Unix domain socket. if (!FLAGS_audit_allow_unix) { return false; } r["family"] = '1'; r["local_port"] = '0'; r["remote_port"] = '0'; off_t begin = (saddr[4] == '0' && saddr[5] == '0') ? 6 : 4; auto end = saddr.substr(begin).find("00"); end = (end == std::string::npos) ? saddr.size() : end + 4; try { r["socket"] = boost::algorithm::unhex(saddr.substr(begin, end - begin)); } catch (const boost::algorithm::hex_decode_error& e) { r["socket"] = "unknown"; } } else { // No idea! return false; } return true; }
int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) { BaseCursor *pCur = (BaseCursor *)cur; const auto *pVtab = (VirtualTable *)cur->pVtab; if (col >= static_cast<int>(pVtab->content->columns.size())) { // Requested column index greater than column set size. return SQLITE_ERROR; } const auto &column_name = pVtab->content->columns[col].first; const auto &type = pVtab->content->columns[col].second; if (pCur->row >= pCur->data.size()) { // Request row index greater than row set size. return SQLITE_ERROR; } // Attempt to cast each xFilter-populated row/column to the SQLite type. const auto &value = pCur->data[pCur->row][column_name]; if (pCur->data[pCur->row].count(column_name) == 0) { // Missing content. VLOG(1) << "Error " << column_name << " is empty"; sqlite3_result_null(ctx); } else if (type == TEXT_TYPE) { sqlite3_result_text(ctx, value.c_str(), value.size(), SQLITE_STATIC); } else if (type == INTEGER_TYPE) { long afinite; if (!safeStrtol(value, 10, afinite) || afinite < INT_MIN || afinite > INT_MAX) { VLOG(1) << "Error casting " << column_name << " (" << value << ") to INTEGER"; sqlite3_result_null(ctx); } else { sqlite3_result_int(ctx, (int)afinite); } } else if (type == BIGINT_TYPE || type == UNSIGNED_BIGINT_TYPE) { long long afinite; if (!safeStrtoll(value, 10, afinite)) { VLOG(1) << "Error casting " << column_name << " (" << value << ") to BIGINT"; sqlite3_result_null(ctx); } else { sqlite3_result_int64(ctx, afinite); } } else if (type == DOUBLE_TYPE) { char *end = nullptr; double afinite = strtod(value.c_str(), &end); if (end == nullptr || end == value.c_str() || *end != '\0') { afinite = 0; VLOG(1) << "Error casting " << column_name << " (" << value << ") to DOUBLE"; sqlite3_result_null(ctx); } else { sqlite3_result_double(ctx, afinite); } } else { LOG(ERROR) << "Error unknown column type " << column_name; } return SQLITE_OK; }
inline void idToHex(std::string& id) { long base = 0; if (safeStrtol(id, 10, base)) { std::stringstream hex_id; hex_id << std::hex << std::setw(4) << std::setfill('0') << (base & 0xFFFF); id = hex_id.str(); } }
size_t getMachineShard(const std::string& hostname = "", bool force = false) { static size_t shard = 0; if (shard > 0 && !force) { return shard; } // An optional input hostname may override hostname detection for testing. auto hn = (hostname.empty()) ? getHostname() : hostname; auto hn_hash = hashFromBuffer(HASH_TYPE_MD5, hn.c_str(), hn.size()); if (hn_hash.size() >= 2) { long hn_char; if (safeStrtol(hn_hash.substr(0, 2), 16, hn_char)) { shard = (hn_char * 100) / 255; } } return shard; }
QueryData genIPv4ArpCache(QueryContext& context) { QueryData results; QueryData interfaces = genInterfaceDetails(context); WmiRequest wmiSystemReq("select * from MSFT_NetNeighbor", (BSTR)L"ROOT\\StandardCimv2"); std::vector<WmiResultItem>& wmiResults = wmiSystemReq.results(); std::map<long, std::string> mapOfInterfaces = { {1, ""}, // loopback }; unsigned short usiPlaceHolder; unsigned char cPlaceHolder; unsigned int uiPlaceHolder; std::string strPlaceHolder; for (const auto& iface : interfaces) { long interfaceIndex; if (iface.count("interface") > 0) { safeStrtol(iface.at("interface"), 10, interfaceIndex); std::string macAddress = iface.at("mac"); mapOfInterfaces.insert(std::make_pair(interfaceIndex, macAddress)); } } for (const auto& item : wmiResults) { Row r; item.GetUnsignedShort("AddressFamily", usiPlaceHolder); r["address_family"] = SQL_TEXT(kMapOfAddressFamily.at(usiPlaceHolder)); item.GetUChar("Store", cPlaceHolder); r["store"] = SQL_TEXT(kMapOfStore.at(cPlaceHolder)); item.GetUChar("State", cPlaceHolder); r["state"] = SQL_TEXT(kMapOfState.at(cPlaceHolder)); item.GetUnsignedInt32("InterfaceIndex", uiPlaceHolder); r["interface"] = SQL_TEXT(mapOfInterfaces.at(uiPlaceHolder)); item.GetString("IPAddress", r["ip_address"]); item.GetString("InterfaceAlias", r["interface_alias"]); item.GetString("LinkLayerAddress", strPlaceHolder); r["link_layer_address"] = SQL_TEXT(boost::replace_all_copy(strPlaceHolder, "-", ":")); results.push_back(r); } return results; }
QueryData genUsers(QueryContext& context) { QueryData results; struct passwd *pwd = nullptr; if (context.constraints["uid"].exists(EQUALS)) { std::set<std::string> uids = context.constraints["uid"].getAll(EQUALS); for (const auto& uid : uids) { long auid{0}; if (safeStrtol(uid, 10, auid) && (pwd = getpwuid(auid)) != nullptr) { genUser(pwd, results); } } } else { std::lock_guard<std::mutex> lock(pwdEnumerationMutex); while ((pwd = getpwent()) != nullptr) { genUser(pwd, results); } endpwent(); } return results; }
void MD::parseMDStat(const std::vector<std::string>& lines, MDStat& result) { // Will be used to determine starting point of lines to work on. size_t n = 0; if (lines.empty()) { return; } // This should always evaluate to true, but just in case we check. if (lines[0].find("Personalities :") != std::string::npos) { std::string pline(lines[0].substr(sizeof("Personalities :") - 1)); parseMDPersonalities(pline, result.personalities); n = 1; } else { LOG(WARNING) << "mdstat Personalites not found at line 0: " << lines[0]; } while (n < lines.size()) { if (lines[n].find_first_not_of("\t\r\v ") == std::string::npos) { n += 1; continue; } // Work off of first 2 character instead of just the first to be safe. std::string firstTwo = lines[n].substr(0, 2); if (firstTwo == "md") { auto mdline(split(lines[n], ":", 1)); if (mdline.size() < 2) { LOG(WARNING) << "Unexpected md device line structure: " << lines[n]; n += 1; continue; } MDDevice mdd; mdd.name = std::move(mdline[0]); boost::algorithm::trim(mdd.name); auto settings(split(mdline[1], " ")); trimStrs(settings); // First 2 of settings are always status and RAID level if (settings.size() >= 2) { mdd.status = std::move(settings[0]); mdd.raidLevel = std::move(settings[1]); for (size_t i = 2; i < settings.size(); i++) { mdd.drives.push_back(parseMDDrive(settings[i])); } } /* Next line is device config and settings. We handle here instead of * later b/c pieces are need for both md_drives and md_devices table. For * safety, we check if we at the end of the file. */ if (n >= lines.size() - 1) { continue; n += 1; } auto configline(split(lines[n + 1])); if (configline.size() < 4) { LOG(WARNING) << "Unexpected md device config: " << lines[n + 1]; } else { trimStrs(configline); if (configline[1] == "blocks") { Status status = safeStrtol(configline[0], 10, mdd.usableSize); if (!status.ok()) { LOG(WARNING) << "Could not parse usable size of " << mdd.name; } } else { LOG(WARNING) << "Did not find size in mdstat for " << mdd.name; } mdd.healthyDrives = configline[configline.size() - 2]; mdd.driveStatuses = configline[configline.size() - 1]; if (configline.size() > 4) { for (size_t i = 2; i < configline.size() - 2; i++) { mdd.other += (" " + configline[i]); boost::algorithm::trim(mdd.other); } } } // Skip config line for next iteration n += 1; // Handle potential bitmap, recovery, and resync lines while (n < lines.size() - 1) { if (handleMDStatuses( lines, n, "recovery =", [&mdd](const std::string& line) { parseMDAction(line, mdd.recovery); })) { continue; } if (handleMDStatuses( lines, n, "resync =", [&mdd](const std::string& line) { parseMDAction(line, mdd.resync); })) { continue; } // If in this format, it's generally signaling a progress delay if (handleMDStatuses( lines, n, "resync=", [&mdd](const std::string& line) { mdd.resync.progress = line; })) { continue; } if (handleMDStatuses( lines, n, "reshape =", [&mdd](const std::string& line) { parseMDAction(line, mdd.reshape); })) { continue; } if (handleMDStatuses( lines, n, "check =", [&mdd](const std::string& line) { parseMDAction(line, mdd.checkArray); })) { continue; } if (handleMDStatuses( lines, n, "bitmap:", [&mdd](const std::string& line) { parseMDBitmap(line, mdd.bitmap); })) { continue; } // If none of above, then we can break out of loop break; } result.devices.push_back(mdd); // Assume unused } else if (firstTwo == "un") { result.unused = lines[n].substr(sizeof("unused devices:") - 1); boost::algorithm::trim(result.unused); // Unexpected mdstat line, log a warning... } else { LOG(WARNING) << "Unexpected mdstat line: " << lines[n]; } n += 1; } }