mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-08 10:23:54 +00:00
77aa36fa0b
This change allows QueryContext constraints to be checked for based on operator type. This makes checks for the existence of an equality operator allow enumeration. Example: if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); } else { osquery::procProcesses(pids); }
176 lines
5.0 KiB
C++
176 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <rpm/rpmlib.h>
|
|
#include <rpm/header.h>
|
|
#include <rpm/rpmts.h>
|
|
#include <rpm/rpmfi.h>
|
|
#include <rpm/rpmdb.h>
|
|
#include <rpm/rpmpgp.h>
|
|
|
|
#include <osquery/filesystem.h>
|
|
#include <osquery/logger.h>
|
|
#include <osquery/tables.h>
|
|
|
|
namespace osquery {
|
|
namespace tables {
|
|
|
|
// Maximum number of files per RPM.
|
|
#define MAX_RPM_FILES 2048
|
|
|
|
/**
|
|
* @brief Return a string representation of the RPM tag type.
|
|
*
|
|
* @param header A librpm header.
|
|
* @param tag A librpm rpmTag_t name.
|
|
* @param td A librpm rpmtd.
|
|
*
|
|
* Given a librpm iterator header and a requested tag name:
|
|
* 1. Determine the type of the tag (the class of value).
|
|
* 2. Request a const pointer or cast of numerate to that class.
|
|
* 3. Lexical-cast the value for SQL.
|
|
*
|
|
* @return The string representation of the tag type.
|
|
*/
|
|
static std::string getRpmAttribute(const Header& header,
|
|
rpmTag tag,
|
|
const rpmtd& td) {
|
|
std::string result;
|
|
if (headerGet(header, tag, td, HEADERGET_DEFAULT) == 0) {
|
|
// Intentional check for a 0 = failure.
|
|
TLOG << "Could not get RPM header flag.";
|
|
return result;
|
|
}
|
|
|
|
if (rpmTagGetClass(tag) == RPM_NUMERIC_CLASS) {
|
|
long long int attr = rpmtdGetNumber(td);
|
|
result = BIGINT(attr);
|
|
} else if (rpmTagGetClass(tag) == RPM_STRING_CLASS) {
|
|
const char* attr = rpmtdGetString(td);
|
|
if (attr != nullptr) {
|
|
result = TEXT(attr);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QueryData genRpmPackages(QueryContext& context) {
|
|
QueryData results;
|
|
// The following implementation uses http://rpm.org/api/4.11.1/
|
|
rpmInitCrypto();
|
|
if (rpmReadConfigFiles(nullptr, nullptr) != 0) {
|
|
TLOG << "Cannot read RPM configuration files.";
|
|
return results;
|
|
}
|
|
|
|
rpmts ts = rpmtsCreate();
|
|
rpmdbMatchIterator matches;
|
|
if (context.constraints["name"].exists(EQUALS)) {
|
|
auto name = (*context.constraints["name"].getAll(EQUALS).begin());
|
|
matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size());
|
|
} else {
|
|
matches = rpmtsInitIterator(ts, RPMTAG_NAME, nullptr, 0);
|
|
}
|
|
|
|
Header header;
|
|
while ((header = rpmdbNextIterator(matches)) != nullptr) {
|
|
Row r;
|
|
rpmtd td = rpmtdNew();
|
|
r["name"] = getRpmAttribute(header, RPMTAG_NAME, td);
|
|
r["version"] = getRpmAttribute(header, RPMTAG_VERSION, td);
|
|
r["release"] = getRpmAttribute(header, RPMTAG_RELEASE, td);
|
|
r["source"] = getRpmAttribute(header, RPMTAG_SOURCERPM, td);
|
|
r["size"] = getRpmAttribute(header, RPMTAG_SIZE, td);
|
|
r["sha1"] = getRpmAttribute(header, RPMTAG_SHA1HEADER, td);
|
|
r["arch"] = getRpmAttribute(header, RPMTAG_ARCH, td);
|
|
|
|
rpmtdFree(td);
|
|
results.push_back(r);
|
|
}
|
|
|
|
rpmdbFreeIterator(matches);
|
|
rpmtsFree(ts);
|
|
rpmFreeCrypto();
|
|
rpmFreeRpmrc();
|
|
|
|
return results;
|
|
}
|
|
|
|
QueryData genRpmPackageFiles(QueryContext& context) {
|
|
QueryData results;
|
|
if (rpmReadConfigFiles(nullptr, nullptr) != 0) {
|
|
TLOG << "Cannot read RPM configuration files.";
|
|
return results;
|
|
}
|
|
|
|
rpmts ts = rpmtsCreate();
|
|
rpmdbMatchIterator matches;
|
|
if (context.constraints["package"].exists(EQUALS)) {
|
|
auto name = (*context.constraints["package"].getAll(EQUALS).begin());
|
|
matches = rpmtsInitIterator(ts, RPMTAG_NAME, name.c_str(), name.size());
|
|
} else {
|
|
matches = rpmtsInitIterator(ts, RPMTAG_NAME, nullptr, 0);
|
|
}
|
|
|
|
Header header;
|
|
while ((header = rpmdbNextIterator(matches)) != nullptr) {
|
|
rpmtd td = rpmtdNew();
|
|
rpmfi fi = rpmfiNew(ts, header, RPMTAG_BASENAMES, RPMFI_NOHEADER);
|
|
auto file_count = rpmfiFC(fi);
|
|
if (file_count <= 0 || file_count > MAX_RPM_FILES) {
|
|
// This package contains no or too many files.
|
|
rpmfiFree(fi);
|
|
continue;
|
|
}
|
|
|
|
// Iterate over every file in this package.
|
|
for (size_t i = 0; rpmfiNext(fi) >= 0 && i < file_count; i++) {
|
|
Row r;
|
|
r["package"] = getRpmAttribute(header, RPMTAG_NAME, td);
|
|
auto path = rpmfiFN(fi);
|
|
r["path"] = (path != nullptr) ? path : "";
|
|
auto username = rpmfiFUser(fi);
|
|
r["username"] = (username != nullptr) ? username : "";
|
|
auto groupname = rpmfiFGroup(fi);
|
|
r["groupname"] = (groupname != nullptr) ? groupname : "";
|
|
r["mode"] = lsperms(rpmfiFMode(fi));
|
|
r["size"] = BIGINT(rpmfiFSize(fi));
|
|
|
|
#if defined(CENTOS_CENTOS6) || defined(RHEL_RHEL6)
|
|
// Older versions of rpmlib/rpmip use a hash algorithm enum.
|
|
pgpHashAlgo digest_algo;
|
|
#else
|
|
int digest_algo;
|
|
#endif
|
|
auto digest = rpmfiFDigestHex(fi, &digest_algo);
|
|
if (digest_algo == PGPHASHALGO_SHA256) {
|
|
r["sha256"] = (digest != nullptr) ? digest : "";
|
|
}
|
|
|
|
results.push_back(r);
|
|
}
|
|
|
|
rpmfiFree(fi);
|
|
rpmtdFree(td);
|
|
}
|
|
|
|
rpmdbFreeIterator(matches);
|
|
rpmtsFree(ts);
|
|
rpmFreeRpmrc();
|
|
|
|
return results;
|
|
}
|
|
}
|
|
}
|