mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6093118ba1 | ||
|
|
6719d4c32a | ||
|
|
1ce4756771 | ||
|
|
9a7dcefb92 | ||
|
|
59382bc3ac | ||
|
|
0725fccc7f | ||
|
|
166c0420e5 | ||
|
|
f4ec2d51ab | ||
|
|
d54ec98bd5 | ||
|
|
bbeb653c77 | ||
|
|
52ffe5fc50 | ||
|
|
ffd77fef9d | ||
|
|
47648d2d5c | ||
|
|
208b4a6ebc | ||
|
|
7f86366672 | ||
|
|
9e7847740f | ||
|
|
348ff8c006 | ||
|
|
476cd21653 | ||
|
|
7bf11abca0 | ||
|
|
466546f548 | ||
|
|
73c18851f9 | ||
|
|
650f6fac97 | ||
|
|
9764f1bd69 | ||
|
|
688d560b62 | ||
|
|
b6af5ade60 | ||
|
|
08ce693096 | ||
|
|
85cfa641ce | ||
|
|
72ed5ee4f9 | ||
|
|
ecf7040b87 | ||
|
|
cedbc0da19 | ||
|
|
ef9348e6f5 | ||
|
|
b23b528082 | ||
|
|
587ac2ddc8 | ||
|
|
14729210d3 | ||
|
|
c3d29e3c4a | ||
|
|
4b0ad39413 | ||
|
|
e8b7fdff64 | ||
|
|
35d42d0134 | ||
|
|
a42dd6e120 | ||
|
|
53a2bbdd1e | ||
|
|
e417d8847f | ||
|
|
a23b67d5de |
7
.github/workflows/check-markdown.yml
vendored
7
.github/workflows/check-markdown.yml
vendored
@@ -10,8 +10,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Santa"
|
||||
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # ratchet:actions/checkout@master
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # ratchet:actions/checkout@v4
|
||||
- name: "Check for deadlinks"
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # ratchet:gaurav-nelson/github-action-markdown-link-check@v1
|
||||
uses: lycheeverse/lychee-action@2b973e86fc7b1f6b36a93795fe2c9c6ae1118621 # ratchet:lycheeverse/lychee-action@v1
|
||||
with:
|
||||
fail: true
|
||||
- name: "Check for trailing whitespace and newlines"
|
||||
if: '!cancelled()'
|
||||
run: "! git grep -EIn $'[ \t]+$' -- ':(exclude)*.patch'"
|
||||
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-11, macos-12, macos-13, macos-14]
|
||||
os: [macos-12, macos-13, macos-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-11, macos-12, macos-13, macos-14]
|
||||
os: [macos-12, macos-13, macos-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
|
||||
|
||||
25
MODULE.bazel
25
MODULE.bazel
@@ -1,20 +1,16 @@
|
||||
module(name = "santa")
|
||||
|
||||
bazel_dep(name = "apple_support", version = "1.15.1", repo_name = "build_bazel_apple_support")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "com_google_absl")
|
||||
bazel_dep(name = "rules_python", version = "0.31.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.2", repo_name = "com_google_absl")
|
||||
bazel_dep(name = "rules_python", version = "0.33.2")
|
||||
bazel_dep(name = "rules_cc", version = "0.0.9")
|
||||
bazel_dep(name = "rules_apple", version = "3.5.0", repo_name = "build_bazel_rules_apple")
|
||||
bazel_dep(name = "rules_swift", version = "1.18.0", repo_name = "build_bazel_rules_swift")
|
||||
bazel_dep(name = "rules_fuzzing", version = "0.5.1")
|
||||
bazel_dep(name = "protobuf", version = "main", repo_name = "com_google_protobuf")
|
||||
git_override(
|
||||
module_name = "protobuf",
|
||||
commit = "21d75f861cdbc03b0a6b235a9ccf3ba0e1f09b32",
|
||||
remote = "https://github.com/protocolbuffers/protobuf.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_apple", version = "3.6.0", repo_name = "build_bazel_rules_apple")
|
||||
bazel_dep(name = "rules_swift", version = "2.0.0-rc1", repo_name = "build_bazel_rules_swift")
|
||||
bazel_dep(name = "rules_fuzzing", version = "0.5.2")
|
||||
bazel_dep(name = "protobuf", version = "27.2", repo_name = "com_google_protobuf")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1", repo_name = "com_google_googletest")
|
||||
|
||||
# MOLCertificate
|
||||
bazel_dep(name = "molcertificate", version = "2.1", repo_name = "MOLCertificate")
|
||||
git_override(
|
||||
module_name = "molcertificate",
|
||||
@@ -22,6 +18,7 @@ git_override(
|
||||
remote = "https://github.com/google/macops-molcertificate.git",
|
||||
)
|
||||
|
||||
# MOLAuthenticatingURLSession
|
||||
bazel_dep(name = "molauthenticatingurlsession", version = "3.0", repo_name = "MOLAuthenticatingURLSession")
|
||||
git_override(
|
||||
module_name = "molauthenticatingurlsession",
|
||||
@@ -29,6 +26,7 @@ git_override(
|
||||
remote = "https://github.com/google/macops-molauthenticatingurlsession.git",
|
||||
)
|
||||
|
||||
# MOLCodesignChecker
|
||||
bazel_dep(name = "molcodesignchecker", version = "3.0", repo_name = "MOLCodesignChecker")
|
||||
git_override(
|
||||
module_name = "molcodesignchecker",
|
||||
@@ -36,6 +34,7 @@ git_override(
|
||||
remote = "https://github.com/google/macops-molcodesignchecker.git",
|
||||
)
|
||||
|
||||
# MOLXPCConnection
|
||||
bazel_dep(name = "molxpcconnection", version = "2.1", repo_name = "MOLXPCConnection")
|
||||
git_override(
|
||||
module_name = "molxpcconnection",
|
||||
@@ -43,10 +42,12 @@ git_override(
|
||||
remote = "https://github.com/russellhancox/macops-molxpcconnection.git",
|
||||
)
|
||||
|
||||
# FMDB
|
||||
non_module_deps = use_extension("//:non_module_deps.bzl", "non_module_deps")
|
||||
use_repo(non_module_deps, "FMDB")
|
||||
use_repo(non_module_deps, "OCMock")
|
||||
|
||||
# Hedron's Compile Commands Extractor
|
||||
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
|
||||
git_override(
|
||||
module_name = "hedron_compile_commands",
|
||||
|
||||
@@ -150,6 +150,16 @@ objc_library(
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "SigningIDHelpers",
|
||||
srcs = ["SigningIDHelpers.m"],
|
||||
hdrs = ["SigningIDHelpers.h"],
|
||||
deps = [
|
||||
":SNTLogging",
|
||||
"@MOLCodesignChecker",
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "SNTBlockMessage",
|
||||
srcs = ["SNTBlockMessage.m"],
|
||||
@@ -477,6 +487,9 @@ santa_unit_test(
|
||||
santa_unit_test(
|
||||
name = "SNTBlockMessageTest",
|
||||
srcs = ["SNTBlockMessageTest.m"],
|
||||
sdk_frameworks = [
|
||||
"AppKit",
|
||||
],
|
||||
deps = [
|
||||
":SNTBlockMessage_SantaGUI",
|
||||
":SNTConfigurator",
|
||||
@@ -485,9 +498,6 @@ santa_unit_test(
|
||||
":SNTSystemInfo",
|
||||
"@OCMock",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"AppKit",
|
||||
],
|
||||
)
|
||||
|
||||
santa_unit_test(
|
||||
@@ -527,6 +537,7 @@ objc_library(
|
||||
"bsm",
|
||||
],
|
||||
deps = [
|
||||
":Platform",
|
||||
":SystemResources",
|
||||
"@OCMock",
|
||||
"@com_google_googletest//:gtest",
|
||||
|
||||
@@ -17,13 +17,6 @@
|
||||
|
||||
#include <Availability.h>
|
||||
|
||||
#if defined(MAC_OS_VERSION_12_0) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
|
||||
#define HAVE_MACOS_12 1
|
||||
#else
|
||||
#define HAVE_MACOS_12 0
|
||||
#endif
|
||||
|
||||
#if defined(MAC_OS_VERSION_13_0) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_0
|
||||
#define HAVE_MACOS_13 1
|
||||
@@ -31,4 +24,18 @@
|
||||
#define HAVE_MACOS_13 0
|
||||
#endif
|
||||
|
||||
#if defined(MAC_OS_VERSION_14_0) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_14_0
|
||||
#define HAVE_MACOS_14 1
|
||||
#else
|
||||
#define HAVE_MACOS_14 0
|
||||
#endif
|
||||
|
||||
#if defined(MAC_OS_VERSION_15_0) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0
|
||||
#define HAVE_MACOS_15 1
|
||||
#else
|
||||
#define HAVE_MACOS_15 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define DEBUG_LOG(format, ...) // NOP
|
||||
#endif
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
template <typename ValueT>
|
||||
class PrefixTree {
|
||||
@@ -125,7 +125,10 @@ class PrefixTree {
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_byte = (uint8_t) * ++p;
|
||||
// Disabling clang format due to local/remote version differences.
|
||||
// clang-format off
|
||||
cur_byte = (uint8_t)*++p;
|
||||
// clang-format on
|
||||
} while (*p);
|
||||
|
||||
node->node_type_ = node_type;
|
||||
@@ -297,6 +300,6 @@ class PrefixTree {
|
||||
absl::Mutex lock_;
|
||||
};
|
||||
|
||||
} // namespace santa::common
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define SANTA_PREFIX_TREE_DEBUG 1
|
||||
#include "Source/common/PrefixTree.h"
|
||||
|
||||
using santa::common::PrefixTree;
|
||||
using santa::PrefixTree;
|
||||
|
||||
@interface PrefixTreeTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -347,6 +347,11 @@
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *eventDetailText;
|
||||
|
||||
///
|
||||
/// This string represents the text to show on the "Dismiss" button in the UI instead of "Dismiss".
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *dismissText;
|
||||
|
||||
///
|
||||
/// In lockdown mode this is the message shown to the user when an unknown binary
|
||||
/// is blocked. If this message is not configured, a reasonable default is provided.
|
||||
@@ -393,11 +398,17 @@
|
||||
///
|
||||
@property(readonly, nonatomic) NSURL *syncBaseURL;
|
||||
|
||||
///
|
||||
/// If enabled, syncing will use binary protobufs for transfer instead
|
||||
/// of JSON. Defaults to NO.
|
||||
///
|
||||
@property(readonly, nonatomic) BOOL syncEnableProtoTransfer;
|
||||
|
||||
///
|
||||
/// Proxy settings for syncing.
|
||||
/// This dictionary is passed directly to NSURLSession. The allowed keys
|
||||
/// are loosely documented at
|
||||
/// https://developer.apple.com/documentation/cfnetwork/global_proxy_settings_constants.
|
||||
/// https://developer.apple.com/documentation/cfnetwork/global-proxy-settings-constants.
|
||||
///
|
||||
@property(readonly, nonatomic) NSDictionary *syncProxyConfig;
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ static NSString *const kMobileConfigDomain = @"com.google.santa";
|
||||
/// The keys managed by a mobileconfig.
|
||||
static NSString *const kStaticRules = @"StaticRules";
|
||||
static NSString *const kSyncBaseURLKey = @"SyncBaseURL";
|
||||
static NSString *const kSyncEnableProtoTransfer = @"SyncEnableProtoTransfer";
|
||||
static NSString *const kSyncProxyConfigKey = @"SyncProxyConfiguration";
|
||||
static NSString *const kSyncExtraHeadersKey = @"SyncExtraHeaders";
|
||||
static NSString *const kSyncEnableCleanSyncEventUpload = @"SyncEnableCleanSyncEventUpload";
|
||||
@@ -96,6 +97,7 @@ static NSString *const kAboutTextKey = @"AboutText";
|
||||
static NSString *const kMoreInfoURLKey = @"MoreInfoURL";
|
||||
static NSString *const kEventDetailURLKey = @"EventDetailURL";
|
||||
static NSString *const kEventDetailTextKey = @"EventDetailText";
|
||||
static NSString *const kDismissTextKey = @"DismissText";
|
||||
static NSString *const kUnknownBlockMessage = @"UnknownBlockMessage";
|
||||
static NSString *const kBannedBlockMessage = @"BannedBlockMessage";
|
||||
static NSString *const kBannedUSBBlockMessage = @"BannedUSBBlockMessage";
|
||||
@@ -226,6 +228,7 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
kMoreInfoURLKey : string,
|
||||
kEventDetailURLKey : string,
|
||||
kEventDetailTextKey : string,
|
||||
kDismissTextKey : string,
|
||||
kUnknownBlockMessage : string,
|
||||
kBannedBlockMessage : string,
|
||||
kBannedUSBBlockMessage : string,
|
||||
@@ -234,6 +237,7 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
kModeNotificationLockdown : string,
|
||||
kStaticRules : array,
|
||||
kSyncBaseURLKey : string,
|
||||
kSyncEnableProtoTransfer : number,
|
||||
kSyncEnableCleanSyncEventUpload : number,
|
||||
kSyncProxyConfigKey : dictionary,
|
||||
kSyncExtraHeadersKey : dictionary,
|
||||
@@ -371,6 +375,10 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncEnableProtoTransfer {
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncExtraHeaders {
|
||||
return [self configStateSet];
|
||||
}
|
||||
@@ -403,6 +411,10 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingDismissText {
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingUnknownBlockMessage {
|
||||
return [self configStateSet];
|
||||
}
|
||||
@@ -719,6 +731,11 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
return url;
|
||||
}
|
||||
|
||||
- (BOOL)syncEnableProtoTransfer {
|
||||
NSNumber *number = self.configState[kSyncEnableProtoTransfer];
|
||||
return number ? [number boolValue] : NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *)syncProxyConfig {
|
||||
return self.configState[kSyncProxyConfigKey];
|
||||
}
|
||||
@@ -763,6 +780,10 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
return self.configState[kEventDetailTextKey];
|
||||
}
|
||||
|
||||
- (NSString *)dismissText {
|
||||
return self.configState[kDismissTextKey];
|
||||
}
|
||||
|
||||
- (NSString *)unknownBlockMessage {
|
||||
return self.configState[kUnknownBlockMessage];
|
||||
}
|
||||
@@ -1048,7 +1069,8 @@ static NSString *const kSyncTypeRequired = @"SyncTypeRequired";
|
||||
}
|
||||
}
|
||||
|
||||
if ([action isEqualToString:@"auditonly"]) {
|
||||
// Note: `auditonly` without an underscore is a deprecated, but still accepted form.
|
||||
if ([action isEqualToString:@"audit_only"] || [action isEqualToString:@"auditonly"]) {
|
||||
return SNTOverrideFileAccessActionAuditOnly;
|
||||
} else if ([action isEqualToString:@"disable"]) {
|
||||
return SNTOverrideFileAccessActionDiable;
|
||||
|
||||
@@ -605,10 +605,15 @@ NSString *SNTMetricMakeStringFromMetricType(SNTMetricType metricType) {
|
||||
|
||||
/** Export current state of the SNTMetricSet as an NSDictionary. */
|
||||
- (NSDictionary *)export {
|
||||
NSDictionary *exported = nil;
|
||||
NSDictionary *exported;
|
||||
|
||||
NSArray *callbacks;
|
||||
@synchronized(self) {
|
||||
callbacks = [_callbacks mutableCopy];
|
||||
}
|
||||
|
||||
// Invoke callbacks to ensure metrics are up to date.
|
||||
for (void (^cb)(void) in _callbacks) {
|
||||
for (void (^cb)(void) in callbacks) {
|
||||
cb();
|
||||
}
|
||||
|
||||
@@ -639,20 +644,9 @@ NSString *SNTMetricStringFromMetricFormatType(SNTMetricFormatType format) {
|
||||
NSDictionary *SNTMetricConvertDatesToISO8601Strings(NSDictionary *metrics) {
|
||||
NSMutableDictionary *mutableMetrics = [metrics mutableCopy];
|
||||
|
||||
id formatter;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSISO8601DateFormatter *isoFormatter = [[NSISO8601DateFormatter alloc] init];
|
||||
|
||||
isoFormatter.formatOptions =
|
||||
NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithFractionalSeconds;
|
||||
formatter = isoFormatter;
|
||||
} else {
|
||||
NSDateFormatter *localFormatter = [[NSDateFormatter alloc] init];
|
||||
[localFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
|
||||
[localFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
|
||||
formatter = localFormatter;
|
||||
}
|
||||
NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
|
||||
formatter.formatOptions =
|
||||
NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithFractionalSeconds;
|
||||
|
||||
for (NSString *metricName in mutableMetrics[@"metrics"]) {
|
||||
NSMutableDictionary *metric = mutableMetrics[@"metrics"][metricName];
|
||||
|
||||
@@ -54,4 +54,19 @@
|
||||
///
|
||||
+ (NSString *)modelIdentifier;
|
||||
|
||||
///
|
||||
/// @return The Santa product version, e.g. 2024.6
|
||||
///
|
||||
+ (NSString *)santaProductVersion;
|
||||
|
||||
///
|
||||
/// @return The Santa build version, e.g. 655965194
|
||||
///
|
||||
+ (NSString *)santaBuildVersion;
|
||||
|
||||
///
|
||||
/// @return The full Santa versoin, e.g. 2024.6.655965194
|
||||
///
|
||||
+ (NSString *)santaFullVersion;
|
||||
|
||||
@end
|
||||
|
||||
@@ -74,6 +74,21 @@
|
||||
return @(model);
|
||||
}
|
||||
|
||||
+ (NSString *)santaProductVersion {
|
||||
NSDictionary *info_dict = [[NSBundle mainBundle] infoDictionary];
|
||||
return info_dict[@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
+ (NSString *)santaBuildVersion {
|
||||
NSDictionary *info_dict = [[NSBundle mainBundle] infoDictionary];
|
||||
return [[info_dict[@"CFBundleVersion"] componentsSeparatedByString:@"."] lastObject];
|
||||
}
|
||||
|
||||
+ (NSString *)santaFullVersion {
|
||||
NSDictionary *info_dict = [[NSBundle mainBundle] infoDictionary];
|
||||
return info_dict[@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
#pragma mark - Internal
|
||||
|
||||
+ (NSDictionary *)_systemVersionDictionary {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/// A block that takes the calculated bundle hash, associated events and hashing time in ms.
|
||||
typedef void (^SNTBundleHashBlock)(NSString *, NSArray<SNTStoredEvent *> *, NSNumber *);
|
||||
|
||||
/// Protocol implemented by santabs and utilized by SantaGUI for bundle hashing
|
||||
/// Protocol implemented by santabundleservice and utilized by SantaGUI for bundle hashing
|
||||
@protocol SNTBundleServiceXPC
|
||||
|
||||
///
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
#include "Source/common/ScopedTypeRef.h"
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
template <typename CFT>
|
||||
using ScopedCFTypeRef = ScopedTypeRef<CFT, (CFT)NULL, CFRetain, CFRelease>;
|
||||
|
||||
} // namespace santa::common
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "Source/common/ScopedCFTypeRef.h"
|
||||
|
||||
using santa::common::ScopedCFTypeRef;
|
||||
using santa::ScopedCFTypeRef;
|
||||
|
||||
@interface ScopedCFTypeRefTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "Source/common/ScopedTypeRef.h"
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
template <typename IOT>
|
||||
using ScopedIOObjectRef =
|
||||
@@ -27,4 +27,4 @@ using ScopedIOObjectRef =
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // namespace santa
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "Source/common/ScopedIOObjectRef.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Utilities.h"
|
||||
|
||||
using santa::common::ScopedIOObjectRef;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::GetDefaultIOKitCommsPort;
|
||||
using santa::GetDefaultIOKitCommsPort;
|
||||
using santa::ScopedIOObjectRef;
|
||||
|
||||
@interface ScopedIOObjectRefTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
template <typename ElementT, ElementT InvalidV, auto RetainFunc,
|
||||
auto ReleaseFunc>
|
||||
@@ -75,6 +75,6 @@ class ScopedTypeRef {
|
||||
ElementT object_;
|
||||
};
|
||||
|
||||
} // namespace santa::common
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
30
Source/common/SigningIDHelpers.h
Normal file
30
Source/common/SigningIDHelpers.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/// Copyright 2024 Google LLC
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// https://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
Return a string representing normalized SigningID (prefixed with TeamID and a
|
||||
colon).
|
||||
|
||||
@param csc A MOLCodesignChecker instance
|
||||
|
||||
@return An NSString formated as teamID:signingID or nil if there isn't a valid signing ID.
|
||||
*/
|
||||
NSString *FormatSigningID(MOLCodesignChecker *csc);
|
||||
|
||||
__END_DECLS
|
||||
33
Source/common/SigningIDHelpers.m
Normal file
33
Source/common/SigningIDHelpers.m
Normal file
@@ -0,0 +1,33 @@
|
||||
/// Copyright 2024 Google LLC
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// https://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/common/SigningIDHelpers.h"
|
||||
#import "Source/common/SNTLogging.h"
|
||||
|
||||
NSString *FormatSigningID(MOLCodesignChecker *csc) {
|
||||
if (!csc.signingID.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!csc.teamID.length) {
|
||||
if (csc.platformBinary) {
|
||||
return [NSString stringWithFormat:@"%@:%@", @"platform", csc.signingID];
|
||||
} else {
|
||||
LOGD(@"unable to format signing ID missing team ID for non-platform binary");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:@"%@:%@", csc.teamID, csc.signingID];
|
||||
}
|
||||
@@ -15,13 +15,14 @@
|
||||
#ifndef SANTA__COMMON__STRING_H
|
||||
#define SANTA__COMMON__STRING_H
|
||||
|
||||
#include <EndpointSecurity/ESTypes.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
static inline std::string_view NSStringToUTF8StringView(NSString *str) {
|
||||
return std::string_view(str.UTF8String, [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
|
||||
@@ -48,6 +49,10 @@ static inline NSString *OptionalStringToNSString(const std::optional<std::string
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace santa::common
|
||||
static inline std::string_view StringTokenToStringView(es_string_token_t es_str) {
|
||||
return std::string_view(es_str.data, es_str.length);
|
||||
}
|
||||
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,5 +83,6 @@ es_message_t MakeESMessage(es_event_type_t et, es_process_t *proc,
|
||||
uint64_t future_deadline_ms = 100000);
|
||||
|
||||
uint32_t MaxSupportedESMessageVersionForCurrentOS();
|
||||
uint32_t MinSupportedESMessageVersion(es_event_type_t event_type);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <mach/mach_time.h>
|
||||
#include <time.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#include "Source/common/SystemResources.h"
|
||||
|
||||
NSString *RepeatedString(NSString *str, NSUInteger len) {
|
||||
@@ -64,7 +66,7 @@ struct stat MakeStat(int offset) {
|
||||
|
||||
es_string_token_t MakeESStringToken(const char *s) {
|
||||
return es_string_token_t{
|
||||
.length = strlen(s),
|
||||
.length = s ? strlen(s) : 0,
|
||||
.data = s,
|
||||
};
|
||||
}
|
||||
@@ -91,25 +93,6 @@ es_process_t MakeESProcess(es_file_t *file, audit_token_t tok, audit_token_t par
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t MaxSupportedESMessageVersionForCurrentOS() {
|
||||
// Notes:
|
||||
// 1. ES message v3 was only in betas.
|
||||
// 2. Message version 7 appeared in macOS 13.3, but features from that are
|
||||
// not currently used. Leaving off support here so as to not require
|
||||
// adding v7 test JSON files.
|
||||
if (@available(macOS 13.0, *)) {
|
||||
return 6;
|
||||
} else if (@available(macOS 12.3, *)) {
|
||||
return 5;
|
||||
} else if (@available(macOS 11.0, *)) {
|
||||
return 4;
|
||||
} else if (@available(macOS 10.15.4, *)) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
es_message_t MakeESMessage(es_event_type_t et, es_process_t *proc, ActionType action_type,
|
||||
uint64_t future_deadline_ms) {
|
||||
es_message_t es_msg = {
|
||||
@@ -134,3 +117,204 @@ void SleepMS(long ms) {
|
||||
XCTAssertEqual(errno, EINTR);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MaxSupportedESMessageVersionForCurrentOS() {
|
||||
// Note 1: This function only returns a subset of versions. This is due to the
|
||||
// minimum supported OS build version as well as features in latest versions
|
||||
// not currently being used. Capping the max means unnecessary duuplicate test
|
||||
// JSON files are not needed.
|
||||
//
|
||||
// Note 2: The following table maps ES message versions to lmin macOS version:
|
||||
// ES Version | macOS Version
|
||||
// 1 | 10.15.0
|
||||
// 2 | 10.15.4
|
||||
// 3 | Only in a beta
|
||||
// 4 | 11.0
|
||||
// 5 | 12.3
|
||||
// 6 | 13.0
|
||||
// 7 | 14.0
|
||||
// 8 | 15.0
|
||||
if (@available(macOS 13.0, *)) {
|
||||
return 6;
|
||||
} else if (@available(macOS 12.3, *)) {
|
||||
return 5;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MinSupportedESMessageVersion(es_event_type_t event_type) {
|
||||
switch (event_type) {
|
||||
// The following events are available beginning in macOS 10.15
|
||||
case ES_EVENT_TYPE_AUTH_EXEC:
|
||||
case ES_EVENT_TYPE_AUTH_OPEN:
|
||||
case ES_EVENT_TYPE_AUTH_KEXTLOAD:
|
||||
case ES_EVENT_TYPE_AUTH_MMAP:
|
||||
case ES_EVENT_TYPE_AUTH_MPROTECT:
|
||||
case ES_EVENT_TYPE_AUTH_MOUNT:
|
||||
case ES_EVENT_TYPE_AUTH_RENAME:
|
||||
case ES_EVENT_TYPE_AUTH_SIGNAL:
|
||||
case ES_EVENT_TYPE_AUTH_UNLINK:
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC:
|
||||
case ES_EVENT_TYPE_NOTIFY_OPEN:
|
||||
case ES_EVENT_TYPE_NOTIFY_FORK:
|
||||
case ES_EVENT_TYPE_NOTIFY_CLOSE:
|
||||
case ES_EVENT_TYPE_NOTIFY_CREATE:
|
||||
case ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA:
|
||||
case ES_EVENT_TYPE_NOTIFY_EXIT:
|
||||
case ES_EVENT_TYPE_NOTIFY_GET_TASK:
|
||||
case ES_EVENT_TYPE_NOTIFY_KEXTLOAD:
|
||||
case ES_EVENT_TYPE_NOTIFY_KEXTUNLOAD:
|
||||
case ES_EVENT_TYPE_NOTIFY_LINK:
|
||||
case ES_EVENT_TYPE_NOTIFY_MMAP:
|
||||
case ES_EVENT_TYPE_NOTIFY_MPROTECT:
|
||||
case ES_EVENT_TYPE_NOTIFY_MOUNT:
|
||||
case ES_EVENT_TYPE_NOTIFY_UNMOUNT:
|
||||
case ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN:
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETATTRLIST:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETEXTATTR:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETFLAGS:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETMODE:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETOWNER:
|
||||
case ES_EVENT_TYPE_NOTIFY_SIGNAL:
|
||||
case ES_EVENT_TYPE_NOTIFY_UNLINK:
|
||||
case ES_EVENT_TYPE_NOTIFY_WRITE:
|
||||
case ES_EVENT_TYPE_AUTH_FILE_PROVIDER_MATERIALIZE:
|
||||
case ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_MATERIALIZE:
|
||||
case ES_EVENT_TYPE_AUTH_FILE_PROVIDER_UPDATE:
|
||||
case ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_UPDATE:
|
||||
case ES_EVENT_TYPE_AUTH_READLINK:
|
||||
case ES_EVENT_TYPE_NOTIFY_READLINK:
|
||||
case ES_EVENT_TYPE_AUTH_TRUNCATE:
|
||||
case ES_EVENT_TYPE_NOTIFY_TRUNCATE:
|
||||
case ES_EVENT_TYPE_AUTH_LINK:
|
||||
case ES_EVENT_TYPE_NOTIFY_LOOKUP:
|
||||
case ES_EVENT_TYPE_AUTH_CREATE:
|
||||
case ES_EVENT_TYPE_AUTH_SETATTRLIST:
|
||||
case ES_EVENT_TYPE_AUTH_SETEXTATTR:
|
||||
case ES_EVENT_TYPE_AUTH_SETFLAGS:
|
||||
case ES_EVENT_TYPE_AUTH_SETMODE:
|
||||
case ES_EVENT_TYPE_AUTH_SETOWNER: return 1;
|
||||
|
||||
// The following events are available beginning in macOS 10.15.1
|
||||
case ES_EVENT_TYPE_AUTH_CHDIR:
|
||||
case ES_EVENT_TYPE_NOTIFY_CHDIR:
|
||||
case ES_EVENT_TYPE_AUTH_GETATTRLIST:
|
||||
case ES_EVENT_TYPE_NOTIFY_GETATTRLIST:
|
||||
case ES_EVENT_TYPE_NOTIFY_STAT:
|
||||
case ES_EVENT_TYPE_NOTIFY_ACCESS:
|
||||
case ES_EVENT_TYPE_AUTH_CHROOT:
|
||||
case ES_EVENT_TYPE_NOTIFY_CHROOT:
|
||||
case ES_EVENT_TYPE_AUTH_UTIMES:
|
||||
case ES_EVENT_TYPE_NOTIFY_UTIMES:
|
||||
case ES_EVENT_TYPE_AUTH_CLONE:
|
||||
case ES_EVENT_TYPE_NOTIFY_CLONE:
|
||||
case ES_EVENT_TYPE_NOTIFY_FCNTL:
|
||||
case ES_EVENT_TYPE_AUTH_GETEXTATTR:
|
||||
case ES_EVENT_TYPE_NOTIFY_GETEXTATTR:
|
||||
case ES_EVENT_TYPE_AUTH_LISTEXTATTR:
|
||||
case ES_EVENT_TYPE_NOTIFY_LISTEXTATTR:
|
||||
case ES_EVENT_TYPE_AUTH_READDIR:
|
||||
case ES_EVENT_TYPE_NOTIFY_READDIR:
|
||||
case ES_EVENT_TYPE_AUTH_DELETEEXTATTR:
|
||||
case ES_EVENT_TYPE_NOTIFY_DELETEEXTATTR:
|
||||
case ES_EVENT_TYPE_AUTH_FSGETPATH:
|
||||
case ES_EVENT_TYPE_NOTIFY_FSGETPATH:
|
||||
case ES_EVENT_TYPE_NOTIFY_DUP:
|
||||
case ES_EVENT_TYPE_AUTH_SETTIME:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETTIME:
|
||||
case ES_EVENT_TYPE_NOTIFY_UIPC_BIND:
|
||||
case ES_EVENT_TYPE_AUTH_UIPC_BIND:
|
||||
case ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT:
|
||||
case ES_EVENT_TYPE_AUTH_UIPC_CONNECT:
|
||||
case ES_EVENT_TYPE_AUTH_EXCHANGEDATA:
|
||||
case ES_EVENT_TYPE_AUTH_SETACL:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETACL: return 1;
|
||||
|
||||
// The following events are available beginning in macOS 10.15.4
|
||||
case ES_EVENT_TYPE_NOTIFY_PTY_GRANT:
|
||||
case ES_EVENT_TYPE_NOTIFY_PTY_CLOSE:
|
||||
case ES_EVENT_TYPE_AUTH_PROC_CHECK:
|
||||
case ES_EVENT_TYPE_NOTIFY_PROC_CHECK:
|
||||
case ES_EVENT_TYPE_AUTH_GET_TASK: return 2;
|
||||
|
||||
// The following events are available beginning in macOS 11.0
|
||||
case ES_EVENT_TYPE_AUTH_SEARCHFS:
|
||||
case ES_EVENT_TYPE_NOTIFY_SEARCHFS:
|
||||
case ES_EVENT_TYPE_AUTH_FCNTL:
|
||||
case ES_EVENT_TYPE_AUTH_IOKIT_OPEN:
|
||||
case ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME:
|
||||
case ES_EVENT_TYPE_NOTIFY_PROC_SUSPEND_RESUME:
|
||||
case ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED:
|
||||
case ES_EVENT_TYPE_NOTIFY_GET_TASK_NAME:
|
||||
case ES_EVENT_TYPE_NOTIFY_TRACE:
|
||||
case ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE:
|
||||
case ES_EVENT_TYPE_AUTH_REMOUNT:
|
||||
case ES_EVENT_TYPE_NOTIFY_REMOUNT: return 4;
|
||||
|
||||
// The following events are available beginning in macOS 11.3
|
||||
case ES_EVENT_TYPE_AUTH_GET_TASK_READ:
|
||||
case ES_EVENT_TYPE_NOTIFY_GET_TASK_READ:
|
||||
case ES_EVENT_TYPE_NOTIFY_GET_TASK_INSPECT: return 4;
|
||||
|
||||
// The following events are available beginning in macOS 12.0
|
||||
case ES_EVENT_TYPE_NOTIFY_SETUID:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETGID:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETEUID:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETEGID:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETREUID:
|
||||
case ES_EVENT_TYPE_NOTIFY_SETREGID:
|
||||
case ES_EVENT_TYPE_AUTH_COPYFILE:
|
||||
case ES_EVENT_TYPE_NOTIFY_COPYFILE: return 4;
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
// The following events are available beginning in macOS 13.0
|
||||
case ES_EVENT_TYPE_NOTIFY_AUTHENTICATION:
|
||||
case ES_EVENT_TYPE_NOTIFY_XP_MALWARE_DETECTED:
|
||||
case ES_EVENT_TYPE_NOTIFY_XP_MALWARE_REMEDIATED:
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN:
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT:
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK:
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK:
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH:
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH:
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN:
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT:
|
||||
case ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN:
|
||||
case ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT:
|
||||
case ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_ADD:
|
||||
case ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_REMOVE: return 6;
|
||||
#endif
|
||||
|
||||
#if HAVE_MACOS_14
|
||||
// The following events are available beginning in macOS 14.0
|
||||
case ES_EVENT_TYPE_NOTIFY_PROFILE_ADD:
|
||||
case ES_EVENT_TYPE_NOTIFY_PROFILE_REMOVE:
|
||||
case ES_EVENT_TYPE_NOTIFY_SU:
|
||||
case ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_PETITION:
|
||||
case ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_JUDGEMENT:
|
||||
case ES_EVENT_TYPE_NOTIFY_SUDO:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_GROUP_ADD:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_GROUP_REMOVE:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_GROUP_SET:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_MODIFY_PASSWORD:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_DISABLE_USER:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_ENABLE_USER:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_ADD:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_REMOVE:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_SET:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_CREATE_USER:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_CREATE_GROUP:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_DELETE_USER:
|
||||
case ES_EVENT_TYPE_NOTIFY_OD_DELETE_GROUP:
|
||||
case ES_EVENT_TYPE_NOTIFY_XPC_CONNECT: return 7;
|
||||
#endif
|
||||
|
||||
#if HAVE_MACOS_15
|
||||
case ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE: return 8;
|
||||
#endif
|
||||
|
||||
default: return UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
#ifndef SANTA__COMMON__UNIT_H
|
||||
#define SANTA__COMMON__UNIT_H
|
||||
|
||||
namespace santa::common {
|
||||
namespace santa {
|
||||
|
||||
struct Unit {};
|
||||
|
||||
} // namespace santa::common
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -538,6 +538,225 @@ message FileAccess {
|
||||
optional PolicyDecision policy_decision = 6;
|
||||
}
|
||||
|
||||
// Session identifier for a graphical session
|
||||
// Note: Identifiers are opaque and have no meaning outside of correlating Santa
|
||||
// events with the same identifier
|
||||
message GraphicalSession {
|
||||
optional uint32 id = 1;
|
||||
}
|
||||
|
||||
// Information about a socket address and its type
|
||||
message SocketAddress {
|
||||
// The socket address
|
||||
optional bytes address = 1;
|
||||
|
||||
enum Type {
|
||||
TYPE_UNKNOWN = 0;
|
||||
TYPE_NONE = 1;
|
||||
TYPE_IPV4 = 2;
|
||||
TYPE_IPV6 = 3;
|
||||
TYPE_NAMED_SOCKET = 4;
|
||||
}
|
||||
|
||||
// The type of the socket address
|
||||
optional Type type = 2;
|
||||
}
|
||||
|
||||
// Information about a user logging in via loginwindow
|
||||
message LoginWindowSessionLogin {
|
||||
// The process that emitted the login event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Name of the user logging in
|
||||
optional UserInfo user = 2;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 3;
|
||||
}
|
||||
|
||||
// Information about a user logging out via loginwindow
|
||||
message LoginWindowSessionLogout {
|
||||
// The process that emitted the logout event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Name of the user logging out
|
||||
optional UserInfo user = 2;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 3;
|
||||
}
|
||||
|
||||
// Information about a user locking their session via loginwindow
|
||||
message LoginWindowSessionLock {
|
||||
// The process that emitted the lock event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Name of the user locking their session
|
||||
optional UserInfo user = 2;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 3;
|
||||
}
|
||||
|
||||
// Information about a user unlocking their session via loginwindow
|
||||
message LoginWindowSessionUnlock {
|
||||
// The process that emitted the unlock event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Name of the user unlocking their session
|
||||
optional UserInfo user = 2;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 3;
|
||||
}
|
||||
|
||||
// Information about loginwindow events
|
||||
message LoginWindowSession {
|
||||
oneof event {
|
||||
LoginWindowSessionLogin login = 1;
|
||||
LoginWindowSessionLogout logout = 2;
|
||||
LoginWindowSessionLock lock = 3;
|
||||
LoginWindowSessionUnlock unlock = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Information about a login event from the `login(1)` utility
|
||||
message Login {
|
||||
// The process that emitted the login event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Whether or not the login was successful
|
||||
optional bool success = 2;
|
||||
|
||||
// Login failure message, if applicable
|
||||
optional bytes failure_message = 3;
|
||||
|
||||
// Information about the user that attempted to log in
|
||||
// Note: `uid` data may not always exist on failed attempts
|
||||
optional UserInfo user = 4;
|
||||
}
|
||||
|
||||
// Information about a logout event from the `login(1)` utility
|
||||
message Logout {
|
||||
// The process that emitted the logout event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Information about the user that logged out
|
||||
optional UserInfo user = 2;
|
||||
}
|
||||
|
||||
// Information about login and logout events from the `login(1)` utility
|
||||
message LoginLogout {
|
||||
oneof event {
|
||||
Login login = 1;
|
||||
Logout logout = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Information related to Screen Sharing attaching to a graphical session
|
||||
message ScreenSharingAttach {
|
||||
// The process that emitted the attach event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Whether or not the attach was successful
|
||||
optional bool success = 2;
|
||||
|
||||
// Source address information
|
||||
optional SocketAddress source = 3;
|
||||
|
||||
// Apple ID of the viewer
|
||||
optional bytes viewer = 4;
|
||||
|
||||
// Type of authentication used
|
||||
optional bytes authentication_type = 5;
|
||||
|
||||
// User that attempted authentication, if applicable
|
||||
optional UserInfo authentication_user = 6;
|
||||
|
||||
// Username of the loginwindow session, if available
|
||||
optional UserInfo session_user = 7;
|
||||
|
||||
// Whether or not there was an existing session
|
||||
optional bool existing_session = 8;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 9;
|
||||
}
|
||||
|
||||
// Information related to Screen Sharing detaching from a graphical session
|
||||
message ScreenSharingDetach {
|
||||
// The process that emitted the detach event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Source address information
|
||||
optional SocketAddress source = 2;
|
||||
|
||||
// Apple ID of the viewer
|
||||
optional bytes viewer = 3;
|
||||
|
||||
// Graphical session information for this session
|
||||
optional GraphicalSession graphical_session = 4;
|
||||
}
|
||||
|
||||
// Information about Screen Sharing attach and detach events
|
||||
message ScreenSharing {
|
||||
oneof event {
|
||||
ScreenSharingAttach attach = 1;
|
||||
ScreenSharingDetach detach = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Information about SSH login events from the macOS OpenSSH implementation
|
||||
message OpenSSHLogin {
|
||||
// The process that emitted the login event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
enum Result {
|
||||
RESULT_UNKNOWN = 0;
|
||||
RESULT_LOGIN_EXCEED_MAXTRIES = 1;
|
||||
RESULT_LOGIN_ROOT_DENIED = 2;
|
||||
RESULT_AUTH_SUCCESS = 3;
|
||||
RESULT_AUTH_FAIL_NONE = 4;
|
||||
RESULT_AUTH_FAIL_PASSWD = 5;
|
||||
RESULT_AUTH_FAIL_KBDINT = 6;
|
||||
RESULT_AUTH_FAIL_PUBKEY = 7;
|
||||
RESULT_AUTH_FAIL_HOSTBASED = 8;
|
||||
RESULT_AUTH_FAIL_GSSAPI = 9;
|
||||
RESULT_INVALID_USER = 10;
|
||||
}
|
||||
|
||||
// The result of the login attempt
|
||||
// Note: Successful if type == `RESULT_AUTH_SUCCESS`
|
||||
optional Result result = 2;
|
||||
|
||||
// Source address of the connection
|
||||
optional SocketAddress source = 3;
|
||||
|
||||
// Name of the user that attempted to login
|
||||
// Note: `uid` data may not always exist on failed attempts
|
||||
optional UserInfo user = 4;
|
||||
}
|
||||
|
||||
// Information about SSH logout events from the macOS OpenSSH implementation
|
||||
message OpenSSHLogout {
|
||||
// The process that emitted the logout event
|
||||
optional ProcessInfoLight instigator = 1;
|
||||
|
||||
// Source address of the connection
|
||||
optional SocketAddress source = 2;
|
||||
|
||||
// Information about the user that logged out
|
||||
optional UserInfo user = 3;
|
||||
}
|
||||
|
||||
// Information about login/logout events from the macOS OpenSSH implementation
|
||||
message OpenSSH {
|
||||
oneof event {
|
||||
OpenSSHLogin login = 1;
|
||||
OpenSSHLogout logout = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// A message encapsulating a single event
|
||||
message SantaMessage {
|
||||
// Machine ID of the host emitting this log
|
||||
@@ -565,6 +784,10 @@ message SantaMessage {
|
||||
Allowlist allowlist = 20;
|
||||
FileAccess file_access = 21;
|
||||
CodesigningInvalidated codesigning_invalidated = 22;
|
||||
LoginWindowSession login_window_session = 23;
|
||||
LoginLogout login_logout = 24;
|
||||
ScreenSharing screen_sharing = 25;
|
||||
OpenSSH open_ssh = 26;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ macos_application(
|
||||
"//conditions:default": None,
|
||||
}),
|
||||
infoplists = ["Info.plist"],
|
||||
minimum_os_version = "11.0",
|
||||
minimum_os_version = "12.0",
|
||||
provisioning_profile = select({
|
||||
"//:adhoc_build": None,
|
||||
"//conditions:default": "//profiles:santa_dev",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<outlet property="foundFileCountLabel" destination="LHV-gV-vyf" id="Sr0-T2-xGx"/>
|
||||
<outlet property="hashingIndicator" destination="VyY-Yg-JOe" id="Yq4-tZ-9ep"/>
|
||||
<outlet property="openEventButton" destination="7ua-5a-uSd" id="9s4-ZA-Vlo"/>
|
||||
<outlet property="dismissEventButton" destination="BbV-3h-mmL" id="5s4-ZB-xlo"/>
|
||||
<outlet property="window" destination="9Bq-yh-54f" id="Uhs-WF-TV9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -286,7 +287,7 @@ DQ
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BbV-3h-mmL" userLabel="Dismiss Button">
|
||||
<rect key="frame" x="271" y="28" width="124" height="34"/>
|
||||
<buttonCell key="cell" type="push" title="Ignore" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XR6-Xa-gP4">
|
||||
<buttonCell key="cell" type="push" title="Dismiss" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XR6-Xa-gP4">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
///
|
||||
@property(weak) IBOutlet NSButton *openEventButton;
|
||||
|
||||
///
|
||||
/// Reference to the "Dismiss Event" button in the XIB. Used to update its title.
|
||||
///
|
||||
@property(weak) IBOutlet NSButton *dismissEventButton;
|
||||
|
||||
///
|
||||
/// The execution event that this window is for
|
||||
///
|
||||
|
||||
@@ -99,6 +99,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
NSString *dismissButtonText = [[SNTConfigurator configurator] dismissText];
|
||||
if (dismissButtonText.length) {
|
||||
[self.dismissEventButton setTitle:dismissButtonText];
|
||||
}
|
||||
|
||||
if (!self.event.needsBundleHash) {
|
||||
[self.bundleHashLabel removeFromSuperview];
|
||||
[self.hashingIndicator removeFromSuperview];
|
||||
|
||||
@@ -50,18 +50,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
customMsg:self.attributedCustomMessage];
|
||||
self.window.delegate = self;
|
||||
|
||||
// Add app to Cmd+Tab and Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
|
||||
|
||||
[super showWindow:sender];
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification {
|
||||
// Remove app from Cmd+Tab and Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyAccessory;
|
||||
[super windowWillClose:notification];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedCustomMessage {
|
||||
return [SNTBlockMessage formatMessage:self.customMessage];
|
||||
}
|
||||
|
||||
@@ -66,18 +66,9 @@
|
||||
|
||||
self.window.delegate = self;
|
||||
|
||||
// Make sure app doesn't appear in Cmd+Tab or Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyAccessory;
|
||||
|
||||
[super showWindow:sender];
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification {
|
||||
// Remove app from Cmd+Tab and Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyAccessory;
|
||||
[super windowWillClose:notification];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedCustomMessage {
|
||||
return [SNTBlockMessage attributedBlockMessageForFileAccessEvent:self.event
|
||||
customMessage:self.customMessage];
|
||||
|
||||
@@ -71,6 +71,8 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
[bc resume];
|
||||
[[bc remoteObjectProxy] spindown];
|
||||
[bc invalidate];
|
||||
// Remove app from Cmd+Tab and Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyAccessory;
|
||||
[NSApp hide:self];
|
||||
}
|
||||
}
|
||||
@@ -101,32 +103,37 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
// If GUI is in silent mode or if there's already a notification queued for
|
||||
// this message, don't do anything else.
|
||||
if ([SNTConfigurator configurator].enableSilentMode) return;
|
||||
if ([self notificationAlreadyQueued:pendingMsg]) return;
|
||||
|
||||
// See if this message has been user-silenced.
|
||||
NSString *messageHash = [pendingMsg messageHash];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
NSDate *silenceDate = [ud objectForKey:silencedNotificationsKey][messageHash];
|
||||
if ([silenceDate isKindOfClass:[NSDate class]]) {
|
||||
NSDate *oneDayAgo = [NSDate dateWithTimeIntervalSinceNow:-86400];
|
||||
if ([silenceDate compare:[NSDate date]] == NSOrderedDescending) {
|
||||
LOGI(@"Notification silence: date is in the future, ignoring");
|
||||
[self updateSilenceDate:nil forHash:messageHash];
|
||||
} else if ([silenceDate compare:oneDayAgo] == NSOrderedAscending) {
|
||||
LOGI(@"Notification silence: date is more than one day ago, ignoring");
|
||||
[self updateSilenceDate:nil forHash:messageHash];
|
||||
} else {
|
||||
LOGI(@"Notification silence: dropping notification for %@", messageHash);
|
||||
return;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([self notificationAlreadyQueued:pendingMsg]) return;
|
||||
|
||||
// See if this message has been user-silenced.
|
||||
NSString *messageHash = [pendingMsg messageHash];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
NSDate *silenceDate = [ud objectForKey:silencedNotificationsKey][messageHash];
|
||||
if ([silenceDate isKindOfClass:[NSDate class]]) {
|
||||
NSDate *oneDayAgo = [NSDate dateWithTimeIntervalSinceNow:-86400];
|
||||
if ([silenceDate compare:[NSDate date]] == NSOrderedDescending) {
|
||||
LOGI(@"Notification silence: date is in the future, ignoring");
|
||||
[self updateSilenceDate:nil forHash:messageHash];
|
||||
} else if ([silenceDate compare:oneDayAgo] == NSOrderedAscending) {
|
||||
LOGI(@"Notification silence: date is more than one day ago, ignoring");
|
||||
[self updateSilenceDate:nil forHash:messageHash];
|
||||
} else {
|
||||
LOGI(@"Notification silence: dropping notification for %@", messageHash);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pendingMsg.delegate = self;
|
||||
[self.pendingNotifications addObject:pendingMsg];
|
||||
pendingMsg.delegate = self;
|
||||
[self.pendingNotifications addObject:pendingMsg];
|
||||
|
||||
if (!self.currentWindowController) {
|
||||
[self showQueuedWindow];
|
||||
}
|
||||
if (!self.currentWindowController) {
|
||||
// Add app to Cmd+Tab and Dock.
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
|
||||
[self showQueuedWindow];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// For blocked execution notifications, post an NSDistributedNotificationCenter
|
||||
|
||||
@@ -28,24 +28,22 @@
|
||||
|
||||
- (OSSystemExtensionReplacementAction)request:(OSSystemExtensionRequest *)request
|
||||
actionForReplacingExtension:(OSSystemExtensionProperties *)old
|
||||
withExtension:
|
||||
(OSSystemExtensionProperties *)new API_AVAILABLE(macos(10.15)) {
|
||||
withExtension:(OSSystemExtensionProperties *)new {
|
||||
NSLog(@"SystemExtension \"%@\" request for replacement", request.identifier);
|
||||
return OSSystemExtensionReplacementActionReplace;
|
||||
}
|
||||
|
||||
- (void)requestNeedsUserApproval:(OSSystemExtensionRequest *)request API_AVAILABLE(macos(10.15)) {
|
||||
- (void)requestNeedsUserApproval:(OSSystemExtensionRequest *)request {
|
||||
NSLog(@"SystemExtension \"%@\" request needs user approval", request.identifier);
|
||||
}
|
||||
|
||||
- (void)request:(OSSystemExtensionRequest *)request
|
||||
didFailWithError:(NSError *)error API_AVAILABLE(macos(10.15)) {
|
||||
- (void)request:(OSSystemExtensionRequest *)request didFailWithError:(NSError *)error {
|
||||
NSLog(@"SystemExtension \"%@\" request did fail: %@", request.identifier, error);
|
||||
exit((int)error.code);
|
||||
}
|
||||
|
||||
- (void)request:(OSSystemExtensionRequest *)request
|
||||
didFinishWithResult:(OSSystemExtensionRequestResult)result API_AVAILABLE(macos(10.15)) {
|
||||
didFinishWithResult:(OSSystemExtensionRequestResult)result {
|
||||
NSLog(@"SystemExtension \"%@\" request did finish: %ld", request.identifier, (long)result);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ objc_library(
|
||||
"//Source/common:SNTStoredEvent",
|
||||
"//Source/common:SNTXPCBundleServiceInterface",
|
||||
"//Source/common:SNTXPCNotifierInterface",
|
||||
"//Source/common:SigningIDHelpers",
|
||||
"@FMDB",
|
||||
"@MOLCodesignChecker",
|
||||
"@MOLXPCConnection",
|
||||
@@ -34,7 +35,7 @@ macos_command_line_application(
|
||||
"--options library,kill,runtime",
|
||||
],
|
||||
infoplists = ["Info.plist"],
|
||||
minimum_os_version = "11.0",
|
||||
minimum_os_version = "12.0",
|
||||
provisioning_profile = select({
|
||||
"//:adhoc_build": None,
|
||||
"//conditions:default": "//profiles:santa_dev",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#import "Source/common/SNTLogging.h"
|
||||
#import "Source/common/SNTStoredEvent.h"
|
||||
#import "Source/common/SNTXPCNotifierInterface.h"
|
||||
#import "Source/common/SigningIDHelpers.h"
|
||||
|
||||
@interface SNTBundleService ()
|
||||
@property MOLXPCConnection *notifierConnection;
|
||||
@@ -228,13 +229,7 @@
|
||||
se.signingChain = cs.certificates;
|
||||
se.cdhash = cs.cdhash;
|
||||
se.teamID = cs.teamID;
|
||||
if (cs.signingID) {
|
||||
if (cs.teamID) {
|
||||
se.signingID = [NSString stringWithFormat:@"%@:%@", cs.teamID, cs.signingID];
|
||||
} else if (cs.platformBinary) {
|
||||
se.signingID = [NSString stringWithFormat:@"platform:%@", cs.signingID];
|
||||
}
|
||||
}
|
||||
se.signingID = FormatSigningID(cs);
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
relatedEvents[se.fileSHA256] = se;
|
||||
|
||||
@@ -76,6 +76,7 @@ objc_library(
|
||||
"//Source/common:SNTXPCControlInterface",
|
||||
"//Source/common:SNTXPCSyncServiceInterface",
|
||||
"//Source/common:SNTXPCUnprivilegedControlInterface",
|
||||
"//Source/common:SigningIDHelpers",
|
||||
"//Source/santasyncservice:sync_lib",
|
||||
"@FMDB",
|
||||
"@MOLCertificate",
|
||||
@@ -93,7 +94,7 @@ macos_command_line_application(
|
||||
"--options library,kill,runtime",
|
||||
],
|
||||
infoplists = ["Info.plist"],
|
||||
minimum_os_version = "11.0",
|
||||
minimum_os_version = "12.0",
|
||||
provisioning_profile = select({
|
||||
"//:adhoc_build": None,
|
||||
"//conditions:default": "//profiles:santa_dev",
|
||||
@@ -121,6 +122,7 @@ santa_unit_test(
|
||||
"//Source/common:SNTStoredEvent",
|
||||
"//Source/common:SNTXPCBundleServiceInterface",
|
||||
"//Source/common:SNTXPCControlInterface",
|
||||
"//Source/common:SigningIDHelpers",
|
||||
"@MOLCertificate",
|
||||
"@MOLCodesignChecker",
|
||||
"@MOLXPCConnection",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#import "Source/common/SNTStoredEvent.h"
|
||||
#import "Source/common/SNTXPCBundleServiceInterface.h"
|
||||
#import "Source/common/SNTXPCControlInterface.h"
|
||||
#import "Source/common/SigningIDHelpers.h"
|
||||
#import "Source/santactl/SNTCommand.h"
|
||||
#import "Source/santactl/SNTCommandController.h"
|
||||
|
||||
@@ -84,6 +85,7 @@ NSString *formattedStringForKeyArray(NSArray<NSString *> *array) {
|
||||
@property(nonatomic) BOOL recursive;
|
||||
@property(nonatomic) BOOL jsonOutput;
|
||||
@property(nonatomic) BOOL bundleInfo;
|
||||
@property(nonatomic) BOOL filterInclusive;
|
||||
@property(nonatomic) NSNumber *certIndex;
|
||||
@property(nonatomic, copy) NSArray<NSString *> *outputKeyList;
|
||||
@property(nonatomic, copy) NSDictionary<NSString *, NSRegularExpression *> *outputFilters;
|
||||
@@ -188,6 +190,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
@" case-insensitive regular expression which must match anywhere in\n"
|
||||
@" the keyed property value for the file's info to be displayed.\n"
|
||||
@" You may specify multiple filters by repeating this flag.\n"
|
||||
@" If multiple filters are specified, any match will display the\n"
|
||||
@" file.\n"
|
||||
@" --filter-inclusive: If multiple filters are specified, they must all match\n"
|
||||
@" for the file to be displayed.\n"
|
||||
@" --bundleinfo: If the file is part of a bundle, will also display bundle\n"
|
||||
@" hash information and hashes of all bundle executables.\n"
|
||||
@" Incompatible with --recursive and --cert-index.\n"
|
||||
@@ -382,16 +388,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
|
||||
NSString *cdhash = csc.cdhash;
|
||||
NSString *teamID = csc.teamID;
|
||||
NSString *identifier = csc.signingID;
|
||||
|
||||
NSString *signingID;
|
||||
if (identifier) {
|
||||
if (teamID) {
|
||||
signingID = [NSString stringWithFormat:@"%@:%@", teamID, identifier];
|
||||
} else if (csc.platformBinary) {
|
||||
signingID = [NSString stringWithFormat:@"platform:%@", identifier];
|
||||
}
|
||||
}
|
||||
NSString *signingID = FormatSigningID(csc);
|
||||
|
||||
struct RuleIdentifiers identifiers = {
|
||||
.cdhash = cdhash,
|
||||
@@ -523,15 +520,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
return ^id(SNTCommandFileInfo *cmd, SNTFileInfo *fileInfo) {
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
|
||||
|
||||
NSString *identifier = csc.signingID;
|
||||
NSString *teamID = csc.teamID;
|
||||
if (!identifier) return nil;
|
||||
if (teamID) {
|
||||
return [NSString stringWithFormat:@"%@:%@", teamID, identifier];
|
||||
} else if (csc.platformBinary) {
|
||||
return [NSString stringWithFormat:@"platform:%@", identifier];
|
||||
}
|
||||
return nil;
|
||||
return FormatSigningID(csc);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -616,6 +605,31 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
|
||||
operationQueue.qualityOfService = NSQualityOfServiceUserInitiated;
|
||||
|
||||
// Limit the number of concurrent operations to 2. By default it is unlimited. Querying for the
|
||||
// `Rule` results in an XPC message to the santa daemon. On an M1 Max we are
|
||||
// seeing issues with dropped XPC messages when there are 64 or more in-flight messages. The
|
||||
// number of in-flight requests to the santa daemon to will be capped to
|
||||
// `maxConcurrentOperationCount`.
|
||||
//
|
||||
// Why 2? We are seeing diminishing wall-time improvements for anything over 2 Qs.
|
||||
//
|
||||
// 1 Q
|
||||
// bazel run //Source/santactl -- fileinfo --recursive --key Path --key Rule /usr/libexec/
|
||||
// 1.16s user 0.92s system 35% cpu 5.775 total
|
||||
|
||||
// 2 Qs
|
||||
// bazel run //Source/santactl -- fileinfo --recursive --key Path --key Rule /usr/libexec/
|
||||
// 1.22s user 1.07s system 62% cpu 3.675 total
|
||||
|
||||
// 4 Qs
|
||||
// bazel run //Source/santactl -- fileinfo --recursive --key Path --key Rule /usr/libexec/
|
||||
// 1.22s user 1.16s system 72% cpu 3.275 total
|
||||
|
||||
// 8 Qs
|
||||
// bazel run //Source/santactl -- fileinfo --recursive --key Path --key Rule /usr/libexec/
|
||||
// 1.25s user 1.26s system 75% cpu 3.304 total
|
||||
operationQueue.maxConcurrentOperationCount = 2;
|
||||
|
||||
if (isDir && self.recursive) {
|
||||
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:path];
|
||||
NSString *file = [dirEnum nextObject];
|
||||
@@ -645,8 +659,29 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
[operationQueue waitUntilAllOperationsAreFinished];
|
||||
}
|
||||
|
||||
- (BOOL)shouldOutputValueToDictionary:(NSMutableDictionary *)outputDict
|
||||
valueForKey:(NSString * (^)(NSString *key))valueForKey {
|
||||
if (self.outputFilters.count == 0) return YES;
|
||||
|
||||
int matches = 0;
|
||||
for (NSString *key in self.outputFilters) {
|
||||
NSString *value = valueForKey(key);
|
||||
NSRegularExpression *regex = self.outputFilters[key];
|
||||
if (![regex firstMatchInString:value options:0 range:NSMakeRange(0, value.length)]) continue;
|
||||
// If this is a value we want to show, store it in the output dictionary.
|
||||
// This does a linear search on an array, but it's a small array.
|
||||
if (outputDict && value.length && [self.outputKeyList containsObject:key]) {
|
||||
outputDict[key] = value;
|
||||
}
|
||||
++matches;
|
||||
}
|
||||
|
||||
return self.filterInclusive ? matches == self.outputFilters.count : matches > 0;
|
||||
}
|
||||
|
||||
// Prints out the info for a single (non-directory) file. Which info is printed is controlled
|
||||
// by the keys in self.outputKeyList.
|
||||
// TODO: Refactor so this method is testable.
|
||||
- (void)printInfoForFile:(NSString *)path {
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:path];
|
||||
if (!fileInfo) {
|
||||
@@ -680,41 +715,31 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
NSDictionary *cert = signingChain[index];
|
||||
|
||||
// Check if we should skip over this item based on outputFilters.
|
||||
BOOL filterMatch = self.outputFilters.count == 0;
|
||||
for (NSString *key in self.outputFilters) {
|
||||
NSString *value = cert[key] ?: @"";
|
||||
NSRegularExpression *regex = self.outputFilters[key];
|
||||
if (![regex firstMatchInString:value options:0 range:NSMakeRange(0, value.length)]) continue;
|
||||
filterMatch = YES;
|
||||
break;
|
||||
BOOL shouldOutput = [self shouldOutputValueToDictionary:nil
|
||||
valueForKey:^NSString *(NSString *key) {
|
||||
return cert[key] ?: @"";
|
||||
}];
|
||||
if (!shouldOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filterMatch) return;
|
||||
|
||||
// Filter out the info we want now, in case JSON output
|
||||
for (NSString *key in self.outputKeyList) {
|
||||
outputDict[key] = cert[key];
|
||||
}
|
||||
} else {
|
||||
// Check if we should skip over this item based on outputFilters. We do this before collecting
|
||||
// Check if we should skip over this item based on outputFilters. We do this before collecting
|
||||
// output info because there's a chance that we can bail out early if a filter doesn't match.
|
||||
// However we also don't want to recompute info, so we save any values that we plan to show.
|
||||
BOOL filterMatch = self.outputFilters.count == 0;
|
||||
for (NSString *key in self.outputFilters) {
|
||||
NSString *value = self.propertyMap[key](self, fileInfo) ?: @"";
|
||||
NSRegularExpression *regex = self.outputFilters[key];
|
||||
if (![regex firstMatchInString:value options:0 range:NSMakeRange(0, value.length)]) continue;
|
||||
// If this is a value we want to show, store it in the output dictionary.
|
||||
// This does a linear search on an array, but it's a small array.
|
||||
if (value.length && [self.outputKeyList containsObject:key]) {
|
||||
outputDict[key] = value;
|
||||
}
|
||||
filterMatch = YES;
|
||||
break;
|
||||
BOOL shouldOutput =
|
||||
[self shouldOutputValueToDictionary:outputDict
|
||||
valueForKey:^NSString *(NSString *key) {
|
||||
return self.propertyMap[key](self, fileInfo) ?: @"";
|
||||
}];
|
||||
if (!shouldOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filterMatch) return;
|
||||
|
||||
// Then fill the outputDict with the rest of the missing values.
|
||||
for (NSString *key in self.outputKeyList) {
|
||||
if (outputDict[key]) continue; // ignore keys that we've already set due to a filter
|
||||
@@ -887,6 +912,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
@"\n--bundleinfo is incompatible with --recursive and --cert-index"];
|
||||
}
|
||||
self.bundleInfo = YES;
|
||||
} else if ([arg caseInsensitiveCompare:@"--filter-inclusive"] == NSOrderedSame) {
|
||||
self.filterInclusive = YES;
|
||||
} else {
|
||||
[paths addObject:arg];
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
typedef id (^SNTAttributeBlock)(SNTCommandFileInfo *, SNTFileInfo *);
|
||||
@property(nonatomic) BOOL recursive;
|
||||
@property(nonatomic) BOOL jsonOutput;
|
||||
@property(nonatomic) BOOL filterInclusive;
|
||||
@property(nonatomic) NSNumber *certIndex;
|
||||
@property(nonatomic, copy) NSArray<NSString *> *outputKeyList;
|
||||
@property(nonatomic) NSDictionary<NSString *, SNTAttributeBlock> *propertyMap;
|
||||
@@ -250,4 +251,10 @@ typedef id (^SNTAttributeBlock)(SNTCommandFileInfo *, SNTFileInfo *);
|
||||
XCTAssertEqualObjects(self.cfi.codeSigned(self.cfi, self.fileInfo), expected);
|
||||
}
|
||||
|
||||
- (void)testParseArgumentsFilterInclusiveTrue {
|
||||
NSArray *filePaths = [self.cfi parseArguments:@[ @"--filter-inclusive", @"/usr/bin/yes" ]];
|
||||
XCTAssertTrue(self.cfi.filterInclusive);
|
||||
XCTAssertTrue([filePaths containsObject:@"/usr/bin/yes"]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -205,6 +205,7 @@ objc_library(
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTRule",
|
||||
"//Source/common:SNTRuleIdentifiers",
|
||||
"//Source/common:SigningIDHelpers",
|
||||
"@FMDB",
|
||||
"@MOLCertificate",
|
||||
"@MOLCodesignChecker",
|
||||
@@ -334,6 +335,7 @@ objc_library(
|
||||
":SNTCompilerController",
|
||||
":SNTEndpointSecurityEventHandler",
|
||||
":SNTEndpointSecurityTreeAwareClient",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:PrefixTree",
|
||||
"//Source/common:SNTConfigurator",
|
||||
"//Source/common:SNTLogging",
|
||||
@@ -471,8 +473,10 @@ objc_library(
|
||||
hdrs = ["EventProviders/EndpointSecurity/Enricher.h"],
|
||||
deps = [
|
||||
":EndpointSecurityEnrichedTypes",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SantaCache",
|
||||
"//Source/common:String",
|
||||
"//Source/santad/ProcessTree:SNTEndpointSecurityAdapter",
|
||||
"//Source/santad/ProcessTree:process_tree",
|
||||
],
|
||||
@@ -551,6 +555,7 @@ objc_library(
|
||||
":EndpointSecuritySerializer",
|
||||
":EndpointSecuritySerializerUtilities",
|
||||
":SNTDecisionCache",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTCachedDecision",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTStoredEvent",
|
||||
@@ -566,6 +571,7 @@ objc_library(
|
||||
":EndpointSecuritySerializer",
|
||||
":EndpointSecuritySerializerUtilities",
|
||||
":SNTDecisionCache",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTCachedDecision",
|
||||
"//Source/common:SNTConfigurator",
|
||||
"//Source/common:SNTLogging",
|
||||
@@ -721,6 +727,7 @@ objc_library(
|
||||
deps = [
|
||||
":EndpointSecurityMessage",
|
||||
":SNTApplicationCoreMetrics",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTCommonEnums",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTMetricSet",
|
||||
@@ -816,6 +823,7 @@ objc_library(
|
||||
"//Source/common:SNTConfigurator",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTMetricSet",
|
||||
"//Source/common:SNTSystemInfo",
|
||||
"//Source/common:SNTXPCControlInterface",
|
||||
"//Source/common:SystemResources",
|
||||
],
|
||||
@@ -837,7 +845,7 @@ macos_bundle(
|
||||
}),
|
||||
infoplists = ["Info.plist"],
|
||||
linkopts = ["-execute"],
|
||||
minimum_os_version = "11.0",
|
||||
minimum_os_version = "12.0",
|
||||
provisioning_profile = select({
|
||||
"//:adhoc_build": None,
|
||||
"//conditions:default": "//profiles:daemon_dev",
|
||||
@@ -928,7 +936,6 @@ santa_unit_test(
|
||||
santa_unit_test(
|
||||
name = "SantadTest",
|
||||
srcs = ["SantadTest.mm"],
|
||||
minimum_os_version = "11.0",
|
||||
sdk_dylibs = [
|
||||
"bsm",
|
||||
"EndpointSecurity",
|
||||
@@ -964,7 +971,6 @@ santa_unit_test(
|
||||
srcs = [
|
||||
"SNTApplicationCoreMetricsTest.mm",
|
||||
],
|
||||
minimum_os_version = "11.0",
|
||||
deps = [
|
||||
":SNTApplicationCoreMetrics",
|
||||
"//Source/common:SNTCommonEnums",
|
||||
@@ -1017,6 +1023,7 @@ santa_unit_test(
|
||||
":EndpointSecuritySerializerBasicString",
|
||||
":MockEndpointSecurityAPI",
|
||||
":SNTDecisionCache",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTCachedDecision",
|
||||
"//Source/common:SNTCommonEnums",
|
||||
"//Source/common:SNTConfigurator",
|
||||
@@ -1041,6 +1048,7 @@ santa_unit_test(
|
||||
":EndpointSecuritySerializerProtobuf",
|
||||
":MockEndpointSecurityAPI",
|
||||
":SNTDecisionCache",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:SNTCachedDecision",
|
||||
"//Source/common:SNTCommonEnums",
|
||||
"//Source/common:SNTConfigurator",
|
||||
@@ -1353,6 +1361,7 @@ santa_unit_test(
|
||||
":MockEndpointSecurityAPI",
|
||||
":SNTCompilerController",
|
||||
":SNTEndpointSecurityRecorder",
|
||||
"//Source/common:Platform",
|
||||
"//Source/common:PrefixTree",
|
||||
"//Source/common:SNTConfigurator",
|
||||
"//Source/common:TestUtils",
|
||||
|
||||
@@ -33,13 +33,7 @@ static const int64_t kTransitiveRuleCullingThreshold = 500000;
|
||||
// Consider transitive rules out of date if they haven't been used in six months.
|
||||
static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
|
||||
|
||||
static void addPathsFromDefaultMuteSet(NSMutableSet *criticalPaths) API_AVAILABLE(macos(12.0)) {
|
||||
// Note: This function uses API introduced in macOS 12, but we want to continue to support
|
||||
// building in older environments. API Availability checks do not help for this use case,
|
||||
// instead we use the following preprocessor macros to conditionally compile these API. The
|
||||
// drawback here is that if a pre-macOS 12 SDK is used to build Santa and it is then deployed
|
||||
// on macOS 12 or later, the dynamic mute set will not be computed.
|
||||
#if HAVE_MACOS_12
|
||||
static void addPathsFromDefaultMuteSet(NSMutableSet *criticalPaths) {
|
||||
// Create a temporary ES client in order to grab the default set of muted paths.
|
||||
// TODO(mlw): Reorganize this code so that a temporary ES client doesn't need to be created
|
||||
es_client_t *client = NULL;
|
||||
@@ -69,7 +63,6 @@ static void addPathsFromDefaultMuteSet(NSMutableSet *criticalPaths) API_AVAILABL
|
||||
|
||||
es_release_muted_paths(mps);
|
||||
es_delete_client(client);
|
||||
#endif
|
||||
}
|
||||
|
||||
@interface SNTRuleTable ()
|
||||
@@ -125,10 +118,8 @@ static void addPathsFromDefaultMuteSet(NSMutableSet *criticalPaths) API_AVAILABL
|
||||
NSMutableSet *superSet = [NSMutableSet setWithSet:fallbackDefaultMuteSet];
|
||||
[superSet unionSet:santaDefinedCriticalPaths];
|
||||
|
||||
if (@available(macOS 12.0, *)) {
|
||||
// Attempt to add the real default mute set
|
||||
addPathsFromDefaultMuteSet(superSet);
|
||||
}
|
||||
// Attempt to add the real default mute set
|
||||
addPathsFromDefaultMuteSet(superSet);
|
||||
|
||||
criticalPaths = [superSet allObjects];
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace santa::santad::data_layer {
|
||||
namespace santa {
|
||||
|
||||
enum class WatchItemPathType {
|
||||
kPrefix,
|
||||
@@ -117,6 +117,6 @@ struct WatchItemPolicy {
|
||||
std::string version = "temp_version";
|
||||
};
|
||||
|
||||
} // namespace santa::santad::data_layer
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,11 +52,11 @@ extern NSString *const kWatchItemConfigKeyProcessesCDHash;
|
||||
extern NSString *const kWatchItemConfigKeyProcessesPlatformBinary;
|
||||
|
||||
// Forward declarations
|
||||
namespace santa::santad::data_layer {
|
||||
namespace santa {
|
||||
class WatchItemsPeer;
|
||||
}
|
||||
|
||||
namespace santa::santad::data_layer {
|
||||
namespace santa {
|
||||
|
||||
struct WatchItemsState {
|
||||
uint64_t rule_count;
|
||||
@@ -69,7 +69,7 @@ class WatchItems : public std::enable_shared_from_this<WatchItems> {
|
||||
public:
|
||||
using VersionAndPolicies =
|
||||
std::pair<std::string, std::vector<std::optional<std::shared_ptr<WatchItemPolicy>>>>;
|
||||
using WatchItemsTree = santa::common::PrefixTree<std::shared_ptr<WatchItemPolicy>>;
|
||||
using WatchItemsTree = santa::PrefixTree<std::shared_ptr<WatchItemPolicy>>;
|
||||
|
||||
// Factory
|
||||
static std::shared_ptr<WatchItems> Create(NSString *config_path,
|
||||
@@ -99,7 +99,7 @@ class WatchItems : public std::enable_shared_from_this<WatchItems> {
|
||||
std::pair<NSString *, NSString *> EventDetailLinkInfo(
|
||||
const std::shared_ptr<WatchItemPolicy> &watch_item);
|
||||
|
||||
friend class santa::santad::data_layer::WatchItemsPeer;
|
||||
friend class santa::WatchItemsPeer;
|
||||
|
||||
private:
|
||||
static std::shared_ptr<WatchItems> CreateInternal(NSString *config_path, NSDictionary *config,
|
||||
@@ -135,6 +135,6 @@ class WatchItems : public std::enable_shared_from_this<WatchItems> {
|
||||
NSString *policy_event_detail_text_ ABSL_GUARDED_BY(lock_);
|
||||
};
|
||||
|
||||
} // namespace santa::santad::data_layer
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
#import "Source/common/Unit.h"
|
||||
#include "Source/santad/DataLayer/WatchItemPolicy.h"
|
||||
|
||||
using santa::common::NSStringToUTF8String;
|
||||
using santa::common::NSStringToUTF8StringView;
|
||||
using santa::common::PrefixTree;
|
||||
using santa::common::Unit;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::data_layer::WatchItemPolicy;
|
||||
using santa::NSStringToUTF8String;
|
||||
using santa::NSStringToUTF8StringView;
|
||||
using santa::PrefixTree;
|
||||
using santa::Unit;
|
||||
using santa::WatchItemPathType;
|
||||
using santa::WatchItemPolicy;
|
||||
|
||||
NSString *const kWatchItemConfigKeyVersion = @"Version";
|
||||
NSString *const kWatchItemConfigKeyEventDetailURL = @"EventDetailURL";
|
||||
@@ -96,13 +96,15 @@ static constexpr NSUInteger kWatchItemConfigEventDetailTextMaxLength = 48;
|
||||
// max is used here.
|
||||
static constexpr NSUInteger kWatchItemConfigEventDetailURLMaxLength = 6000;
|
||||
|
||||
namespace santa::santad::data_layer {
|
||||
namespace santa {
|
||||
|
||||
namespace {
|
||||
// Type aliases
|
||||
using ValidatorBlock = bool (^)(id, NSError **);
|
||||
using PathAndTypePair = std::pair<std::string, WatchItemPathType>;
|
||||
using PathList = std::vector<PathAndTypePair>;
|
||||
using ProcessList = std::vector<WatchItemPolicy::Process>;
|
||||
using PathAndTypeVec = std::vector<PathAndTypePair>;
|
||||
using PolicyProcessVec = std::vector<WatchItemPolicy::Process>;
|
||||
} // namespace
|
||||
|
||||
static void PopulateError(NSError **err, NSString *msg) {
|
||||
if (err) {
|
||||
@@ -265,8 +267,8 @@ bool VerifyConfigKeyArray(NSDictionary *dict, NSString *key, Class expected, NSE
|
||||
/// <true/>
|
||||
/// </dict>
|
||||
/// </array>
|
||||
std::variant<Unit, PathList> VerifyConfigWatchItemPaths(NSArray<id> *paths, NSError **err) {
|
||||
PathList path_list;
|
||||
std::variant<Unit, PathAndTypeVec> VerifyConfigWatchItemPaths(NSArray<id> *paths, NSError **err) {
|
||||
PathAndTypeVec path_list;
|
||||
|
||||
for (id path in paths) {
|
||||
if ([path isKindOfClass:[NSDictionary class]]) {
|
||||
@@ -336,9 +338,9 @@ std::variant<Unit, PathList> VerifyConfigWatchItemPaths(NSArray<id> *paths, NSEr
|
||||
/// <string>EEEE</string>
|
||||
/// </dict>
|
||||
/// </array>
|
||||
std::variant<Unit, ProcessList> VerifyConfigWatchItemProcesses(NSDictionary *watch_item,
|
||||
NSError **err) {
|
||||
__block ProcessList proc_list;
|
||||
std::variant<Unit, PolicyProcessVec> VerifyConfigWatchItemProcesses(NSDictionary *watch_item,
|
||||
NSError **err) {
|
||||
__block PolicyProcessVec proc_list;
|
||||
|
||||
if (!VerifyConfigKeyArray(
|
||||
watch_item, kWatchItemConfigKeyProcesses, [NSDictionary class], err,
|
||||
@@ -429,7 +431,7 @@ bool ParseConfigSingleWatchItem(NSString *name, NSDictionary *watch_item,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::variant<Unit, PathList> path_list =
|
||||
std::variant<Unit, PathAndTypeVec> path_list =
|
||||
VerifyConfigWatchItemPaths(watch_item[kWatchItemConfigKeyPaths], err);
|
||||
|
||||
if (std::holds_alternative<Unit>(path_list)) {
|
||||
@@ -485,19 +487,19 @@ bool ParseConfigSingleWatchItem(NSString *name, NSDictionary *watch_item,
|
||||
bool enable_silent_tty_mode = GetBoolValue(options, kWatchItemConfigKeyOptionsEnableSilentTTYMode,
|
||||
kWatchItemPolicyDefaultEnableSilentTTYMode);
|
||||
|
||||
std::variant<Unit, ProcessList> proc_list = VerifyConfigWatchItemProcesses(watch_item, err);
|
||||
std::variant<Unit, PolicyProcessVec> proc_list = VerifyConfigWatchItemProcesses(watch_item, err);
|
||||
if (std::holds_alternative<Unit>(proc_list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const PathAndTypePair &path_type_pair : std::get<PathList>(path_list)) {
|
||||
for (const PathAndTypePair &path_type_pair : std::get<PathAndTypeVec>(path_list)) {
|
||||
policies.push_back(std::make_shared<WatchItemPolicy>(
|
||||
NSStringToUTF8StringView(name), path_type_pair.first, path_type_pair.second,
|
||||
allow_read_access, audit_only, invert_process_exceptions, enable_silent_mode,
|
||||
enable_silent_tty_mode,
|
||||
NSStringToUTF8StringView(options[kWatchItemConfigKeyOptionsCustomMessage]),
|
||||
options[kWatchItemConfigKeyOptionsEventDetailURL],
|
||||
options[kWatchItemConfigKeyOptionsEventDetailText], std::get<ProcessList>(proc_list)));
|
||||
options[kWatchItemConfigKeyOptionsEventDetailText], std::get<PolicyProcessVec>(proc_list)));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -897,4 +899,4 @@ std::pair<NSString *, NSString *> WatchItems::EventDetailLinkInfo(
|
||||
return {url, text};
|
||||
}
|
||||
|
||||
} // namespace santa::santad::data_layer
|
||||
} // namespace santa
|
||||
|
||||
@@ -32,23 +32,23 @@
|
||||
#include "Source/santad/DataLayer/WatchItemPolicy.h"
|
||||
#include "Source/santad/DataLayer/WatchItems.h"
|
||||
|
||||
using santa::common::Unit;
|
||||
using santa::santad::data_layer::kWatchItemPolicyDefaultAllowReadAccess;
|
||||
using santa::santad::data_layer::kWatchItemPolicyDefaultAuditOnly;
|
||||
using santa::santad::data_layer::kWatchItemPolicyDefaultInvertProcessExceptions;
|
||||
using santa::santad::data_layer::kWatchItemPolicyDefaultPathType;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::data_layer::WatchItemPolicy;
|
||||
using santa::santad::data_layer::WatchItems;
|
||||
using santa::santad::data_layer::WatchItemsState;
|
||||
using santa::kWatchItemPolicyDefaultAllowReadAccess;
|
||||
using santa::kWatchItemPolicyDefaultAuditOnly;
|
||||
using santa::kWatchItemPolicyDefaultInvertProcessExceptions;
|
||||
using santa::kWatchItemPolicyDefaultPathType;
|
||||
using santa::Unit;
|
||||
using santa::WatchItemPathType;
|
||||
using santa::WatchItemPolicy;
|
||||
using santa::WatchItems;
|
||||
using santa::WatchItemsState;
|
||||
|
||||
namespace santatest {
|
||||
namespace {
|
||||
using PathAndTypePair = std::pair<std::string, WatchItemPathType>;
|
||||
using PathList = std::vector<PathAndTypePair>;
|
||||
using ProcessList = std::vector<WatchItemPolicy::Process>;
|
||||
} // namespace santatest
|
||||
using PathAndTypeVec = std::vector<PathAndTypePair>;
|
||||
using PolicyProcessVec = std::vector<WatchItemPolicy::Process>;
|
||||
} // namespace
|
||||
|
||||
namespace santa::santad::data_layer {
|
||||
namespace santa {
|
||||
|
||||
extern bool ParseConfig(NSDictionary *config,
|
||||
std::vector<std::shared_ptr<WatchItemPolicy>> &policies, NSError **err);
|
||||
@@ -56,10 +56,10 @@ extern bool IsWatchItemNameValid(NSString *watch_item_name, NSError **err);
|
||||
extern bool ParseConfigSingleWatchItem(NSString *name, NSDictionary *watch_item,
|
||||
std::vector<std::shared_ptr<WatchItemPolicy>> &policies,
|
||||
NSError **err);
|
||||
extern std::variant<Unit, santatest::PathList> VerifyConfigWatchItemPaths(NSArray<id> *paths,
|
||||
NSError **err);
|
||||
extern std::variant<Unit, santatest::ProcessList> VerifyConfigWatchItemProcesses(
|
||||
NSDictionary *watch_item, NSError **err);
|
||||
extern std::variant<Unit, PathAndTypeVec> VerifyConfigWatchItemPaths(NSArray<id> *paths,
|
||||
NSError **err);
|
||||
extern std::variant<Unit, PolicyProcessVec> VerifyConfigWatchItemProcesses(NSDictionary *watch_item,
|
||||
NSError **err);
|
||||
class WatchItemsPeer : public WatchItems {
|
||||
public:
|
||||
using WatchItems::WatchItems;
|
||||
@@ -72,14 +72,14 @@ class WatchItemsPeer : public WatchItems {
|
||||
using WatchItems::embedded_config_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::data_layer
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::data_layer::IsWatchItemNameValid;
|
||||
using santa::santad::data_layer::ParseConfig;
|
||||
using santa::santad::data_layer::ParseConfigSingleWatchItem;
|
||||
using santa::santad::data_layer::VerifyConfigWatchItemPaths;
|
||||
using santa::santad::data_layer::VerifyConfigWatchItemProcesses;
|
||||
using santa::santad::data_layer::WatchItemsPeer;
|
||||
using santa::IsWatchItemNameValid;
|
||||
using santa::ParseConfig;
|
||||
using santa::ParseConfigSingleWatchItem;
|
||||
using santa::VerifyConfigWatchItemPaths;
|
||||
using santa::VerifyConfigWatchItemProcesses;
|
||||
using santa::WatchItemsPeer;
|
||||
|
||||
static constexpr std::string_view kBadPolicyName("__BAD_NAME__");
|
||||
static constexpr std::string_view kBadPolicyPath("__BAD_PATH__");
|
||||
@@ -440,7 +440,7 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
}
|
||||
|
||||
- (void)testVerifyConfigWatchItemPaths {
|
||||
std::variant<Unit, santatest::PathList> path_list;
|
||||
std::variant<Unit, PathAndTypeVec> path_list;
|
||||
NSError *err;
|
||||
|
||||
// Test no paths specified
|
||||
@@ -466,29 +466,28 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
|
||||
// Test path array dictionary with default path type
|
||||
path_list = VerifyConfigWatchItemPaths(@[ @{kWatchItemConfigKeyPathsPath : @"A"} ], &err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::PathList>(path_list));
|
||||
XCTAssertEqual(std::get<santatest::PathList>(path_list).size(), 1);
|
||||
XCTAssertCStringEqual(std::get<santatest::PathList>(path_list)[0].first.c_str(), "A");
|
||||
XCTAssertEqual(std::get<santatest::PathList>(path_list)[0].second,
|
||||
kWatchItemPolicyDefaultPathType);
|
||||
XCTAssertTrue(std::holds_alternative<PathAndTypeVec>(path_list));
|
||||
XCTAssertEqual(std::get<PathAndTypeVec>(path_list).size(), 1);
|
||||
XCTAssertCStringEqual(std::get<PathAndTypeVec>(path_list)[0].first.c_str(), "A");
|
||||
XCTAssertEqual(std::get<PathAndTypeVec>(path_list)[0].second, kWatchItemPolicyDefaultPathType);
|
||||
|
||||
// Test path array dictionary with custom path type
|
||||
path_list = VerifyConfigWatchItemPaths(
|
||||
@[ @{kWatchItemConfigKeyPathsPath : @"A", kWatchItemConfigKeyPathsIsPrefix : @(YES)} ], &err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::PathList>(path_list));
|
||||
XCTAssertEqual(std::get<santatest::PathList>(path_list).size(), 1);
|
||||
XCTAssertCStringEqual(std::get<santatest::PathList>(path_list)[0].first.c_str(), "A");
|
||||
XCTAssertEqual(std::get<santatest::PathList>(path_list)[0].second, WatchItemPathType::kPrefix);
|
||||
XCTAssertTrue(std::holds_alternative<PathAndTypeVec>(path_list));
|
||||
XCTAssertEqual(std::get<PathAndTypeVec>(path_list).size(), 1);
|
||||
XCTAssertCStringEqual(std::get<PathAndTypeVec>(path_list)[0].first.c_str(), "A");
|
||||
XCTAssertEqual(std::get<PathAndTypeVec>(path_list)[0].second, WatchItemPathType::kPrefix);
|
||||
}
|
||||
|
||||
- (void)testVerifyConfigWatchItemProcesses {
|
||||
std::variant<Unit, santatest::ProcessList> proc_list;
|
||||
std::variant<Unit, PolicyProcessVec> proc_list;
|
||||
NSError *err;
|
||||
|
||||
// Non-existent process list parses successfully, but has no items
|
||||
proc_list = VerifyConfigWatchItemProcesses(@{}, &err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 0);
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 0);
|
||||
|
||||
// Process list fails to parse if contains non-array type
|
||||
proc_list = VerifyConfigWatchItemProcesses(@{kWatchItemConfigKeyProcesses : @""}, &err);
|
||||
@@ -498,7 +497,7 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
proc_list = VerifyConfigWatchItemProcesses(@{kWatchItemConfigKeyProcesses : @{}}, &err);
|
||||
XCTAssertTrue(std::holds_alternative<Unit>(proc_list));
|
||||
proc_list = VerifyConfigWatchItemProcesses(@{kWatchItemConfigKeyProcesses : @[]}, &err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
|
||||
// Test a process dictionary with no valid attributes set
|
||||
proc_list = VerifyConfigWatchItemProcesses(@{kWatchItemConfigKeyProcesses : @[ @{} ]}, &err);
|
||||
@@ -516,9 +515,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
proc_list = VerifyConfigWatchItemProcesses(
|
||||
@{kWatchItemConfigKeyProcesses : @[ @{kWatchItemConfigKeyProcessesBinaryPath : @"mypath"} ]},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("mypath", "", "", {}, "", std::nullopt));
|
||||
|
||||
// Test SigningID length limits
|
||||
@@ -535,9 +534,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
@[ @{kWatchItemConfigKeyProcessesSigningID : @"com.google.test"} ]
|
||||
},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("", "com.google.test", "", {}, "", std::nullopt));
|
||||
|
||||
// Test TeamID length limits
|
||||
@@ -552,9 +551,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
proc_list = VerifyConfigWatchItemProcesses(
|
||||
@{kWatchItemConfigKeyProcesses : @[ @{kWatchItemConfigKeyProcessesTeamID : @"myvalidtid"} ]},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("", "", "myvalidtid", {}, "", std::nullopt));
|
||||
|
||||
// Test CDHash length limits
|
||||
@@ -579,9 +578,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
std::fill(cdhashBytes.begin(), cdhashBytes.end(), 0xAA);
|
||||
proc_list = VerifyConfigWatchItemProcesses(
|
||||
@{kWatchItemConfigKeyProcesses : @[ @{kWatchItemConfigKeyProcessesCDHash : cdhash} ]}, &err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("", "", "", cdhashBytes, "", std::nullopt));
|
||||
|
||||
// Test Cert Hash length limits
|
||||
@@ -610,9 +609,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
kWatchItemConfigKeyProcesses : @[ @{kWatchItemConfigKeyProcessesCertificateSha256 : certHash} ]
|
||||
},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("", "", "", {}, [certHash UTF8String], std::nullopt));
|
||||
|
||||
// Test valid invalid PlatformBinary type
|
||||
@@ -625,9 +624,9 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
proc_list = VerifyConfigWatchItemProcesses(
|
||||
@{kWatchItemConfigKeyProcesses : @[ @{kWatchItemConfigKeyProcessesPlatformBinary : @(YES)} ]},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 1);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("", "", "", {}, "", std::make_optional(true)));
|
||||
|
||||
// Test valid multiple attributes, multiple procs
|
||||
@@ -652,12 +651,12 @@ static NSMutableDictionary *WrapWatchItemsConfig(NSDictionary *config) {
|
||||
]
|
||||
},
|
||||
&err);
|
||||
XCTAssertTrue(std::holds_alternative<santatest::ProcessList>(proc_list));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list).size(), 2);
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[0],
|
||||
XCTAssertTrue(std::holds_alternative<PolicyProcessVec>(proc_list));
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list).size(), 2);
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[0],
|
||||
WatchItemPolicy::Process("mypath1", "com.google.test1", "validtid_1", cdhashBytes,
|
||||
[certHash UTF8String], std::make_optional(true)));
|
||||
XCTAssertEqual(std::get<santatest::ProcessList>(proc_list)[1],
|
||||
XCTAssertEqual(std::get<PolicyProcessVec>(proc_list)[1],
|
||||
WatchItemPolicy::Process("mypath2", "com.google.test2", "validtid_2", cdhashBytes,
|
||||
[certHash UTF8String], std::make_optional(false)));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#import "Source/common/SantaVnode.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
|
||||
enum class FlushCacheMode {
|
||||
kNonRootOnly,
|
||||
@@ -52,13 +52,12 @@ class AuthResultCache {
|
||||
// previously denied binary is allowed, it can be re-executed by the user in a
|
||||
// timely manner. But the value should be high enough to allow the cache to be
|
||||
// effective in the event the binary is executed in rapid succession.
|
||||
static std::unique_ptr<AuthResultCache> Create(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTMetricSet *metric_set, uint64_t cache_deny_time_ms = 1500);
|
||||
static std::unique_ptr<AuthResultCache> Create(std::shared_ptr<santa::EndpointSecurityAPI> esapi,
|
||||
SNTMetricSet *metric_set,
|
||||
uint64_t cache_deny_time_ms = 1500);
|
||||
|
||||
AuthResultCache(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTMetricCounter *flush_count, uint64_t cache_deny_time_ms = 1500);
|
||||
AuthResultCache(std::shared_ptr<santa::EndpointSecurityAPI> esapi, SNTMetricCounter *flush_count,
|
||||
uint64_t cache_deny_time_ms = 1500);
|
||||
virtual ~AuthResultCache();
|
||||
|
||||
AuthResultCache(AuthResultCache &&other) = delete;
|
||||
@@ -81,13 +80,13 @@ class AuthResultCache {
|
||||
SantaCache<SantaVnode, uint64_t> *root_cache_;
|
||||
SantaCache<SantaVnode, uint64_t> *nonroot_cache_;
|
||||
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi_;
|
||||
std::shared_ptr<santa::EndpointSecurityAPI> esapi_;
|
||||
SNTMetricCounter *flush_count_;
|
||||
uint64_t root_devno_;
|
||||
uint64_t cache_deny_time_ns_;
|
||||
dispatch_queue_t q_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#import "Source/common/SantaVnodeHash.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Client.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::Client;
|
||||
using santa::EndpointSecurityAPI;
|
||||
|
||||
static NSString *const kFlushCacheReasonClientModeChanged = @"ClientModeChanged";
|
||||
static NSString *const kFlushCacheReasonPathRegexChanged = @"PathRegexChanged";
|
||||
@@ -36,7 +36,7 @@ static NSString *const kFlushCacheReasonEntitlementsPrefixFilterChanged =
|
||||
static NSString *const kFlushCacheReasonEntitlementsTeamIDFilterChanged =
|
||||
@"EntitlementsTeamIDFilterChanged";
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
|
||||
static inline uint64_t GetCurrentUptime() {
|
||||
return clock_gettime_nsec_np(CLOCK_MONOTONIC);
|
||||
@@ -185,4 +185,4 @@ NSArray<NSNumber *> *AuthResultCache::CacheCounts() {
|
||||
return @[ @(root_cache_->count()), @(nonroot_cache_->count()) ];
|
||||
}
|
||||
|
||||
} // namespace santa::santad::event_providers
|
||||
} // namespace santa
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
#include "Source/santad/EventProviders/AuthResultCache.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/MockEndpointSecurityAPI.h"
|
||||
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::FlushCacheMode;
|
||||
using santa::santad::event_providers::FlushCacheReason;
|
||||
using santa::AuthResultCache;
|
||||
using santa::FlushCacheMode;
|
||||
using santa::FlushCacheReason;
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
extern NSString *const FlushCacheReasonToString(FlushCacheReason reason);
|
||||
}
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::event_providers::FlushCacheReasonToString;
|
||||
using santa::FlushCacheReasonToString;
|
||||
|
||||
// Grab the st_dev number of the root volume to match the root cache
|
||||
static uint64_t RootDevno() {
|
||||
|
||||
@@ -150,15 +150,18 @@ void DARegisterDiskAppearedCallback(DASessionRef session, CFDictionaryRef __null
|
||||
}];
|
||||
}
|
||||
|
||||
// Disabling clang format due to local/remote version differences.
|
||||
// clang-format off
|
||||
void DARegisterDiskDisappearedCallback(DASessionRef session, CFDictionaryRef __nullable match,
|
||||
DADiskDisappearedCallback callback,
|
||||
void *__nullable context){};
|
||||
void *__nullable context) {}
|
||||
|
||||
void DARegisterDiskDescriptionChangedCallback(DASessionRef session,
|
||||
CFDictionaryRef __nullable match,
|
||||
CFArrayRef __nullable watch,
|
||||
DADiskDescriptionChangedCallback callback,
|
||||
void *__nullable context){};
|
||||
void *__nullable context) {}
|
||||
// clang-format on
|
||||
|
||||
void DASessionSetDispatchQueue(DASessionRef session, dispatch_queue_t __nullable queue) {
|
||||
MockDiskArbitration *mockDA = [MockDiskArbitration mockDiskArbitration];
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class Client {
|
||||
public:
|
||||
@@ -64,6 +64,6 @@ class Client {
|
||||
es_new_client_result_t result_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Client.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::Client;
|
||||
|
||||
// Global semaphore used for custom `es_delete_client` function
|
||||
dispatch_semaphore_t gSema;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Client.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class EndpointSecurityAPI : public std::enable_shared_from_this<EndpointSecurityAPI> {
|
||||
public:
|
||||
@@ -43,9 +43,9 @@ class EndpointSecurityAPI : public std::enable_shared_from_this<EndpointSecurity
|
||||
virtual bool InvertTargetPathMuting(const Client &client);
|
||||
|
||||
virtual bool MuteTargetPath(const Client &client, std::string_view path,
|
||||
santa::santad::data_layer::WatchItemPathType path_type);
|
||||
santa::WatchItemPathType path_type);
|
||||
virtual bool UnmuteTargetPath(const Client &client, std::string_view path,
|
||||
santa::santad::data_layer::WatchItemPathType path_type);
|
||||
santa::WatchItemPathType path_type);
|
||||
|
||||
virtual void RetainMessage(const es_message_t *msg);
|
||||
virtual void ReleaseMessage(const es_message_t *msg);
|
||||
@@ -69,6 +69,6 @@ class EndpointSecurityAPI : public std::enable_shared_from_this<EndpointSecurity
|
||||
virtual const es_fd_t *ExecFD(const es_event_exec_t *event, uint32_t index);
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::WatchItemPathType;
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
Client EndpointSecurityAPI::NewClient(void (^message_handler)(es_client_t *, Message)) {
|
||||
es_client_t *client = NULL;
|
||||
@@ -156,19 +156,11 @@ es_string_token_t EndpointSecurityAPI::ExecEnv(const es_event_exec_t *event, uin
|
||||
}
|
||||
|
||||
uint32_t EndpointSecurityAPI::ExecFDCount(const es_event_exec_t *event) {
|
||||
if (@available(macOS 11.0, *)) {
|
||||
return es_exec_fd_count(event);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return es_exec_fd_count(event);
|
||||
}
|
||||
|
||||
const es_fd_t *EndpointSecurityAPI::ExecFD(const es_event_exec_t *event, uint32_t index) {
|
||||
if (@available(macOS 11.0, *)) {
|
||||
return es_exec_fd(event, index);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return es_exec_fd(event, index);
|
||||
}
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/ProcessTree/process_tree.pb.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class EnrichedFile {
|
||||
public:
|
||||
@@ -151,7 +151,8 @@ class EnrichedEventType {
|
||||
|
||||
virtual ~EnrichedEventType() = default;
|
||||
|
||||
const es_message_t &es_msg() const { return *es_msg_; }
|
||||
inline const es_message_t *operator->() const { return es_msg_.operator->(); }
|
||||
|
||||
const EnrichedProcess &instigator() const { return instigator_; }
|
||||
struct timespec enrichment_time() const {
|
||||
// No reason to return a reference
|
||||
@@ -340,10 +341,108 @@ class EnrichedCSInvalidated : public EnrichedEventType {
|
||||
EnrichedCSInvalidated(const EnrichedCSInvalidated &other) = delete;
|
||||
};
|
||||
|
||||
using EnrichedType =
|
||||
std::variant<EnrichedClose, EnrichedExchange, EnrichedExec, EnrichedExit,
|
||||
EnrichedFork, EnrichedLink, EnrichedRename, EnrichedUnlink,
|
||||
EnrichedCSInvalidated>;
|
||||
// Note: All EnrichedLoginWindowSession* classes currently have the same
|
||||
// data and implementation. To improve maintainability but still provide
|
||||
// individual types, an internal EnrichedLoginWindowSession base class is
|
||||
// defined that is derived by each desired types.
|
||||
// EnrichedLoginWindowSession is wrapped in an `internal` namespace as it
|
||||
// shouldn't be directly used outside of this file.
|
||||
namespace internal {
|
||||
|
||||
class EnrichedLoginWindowSession : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedLoginWindowSession(Message &&es_msg, EnrichedProcess instigator,
|
||||
std::optional<uid_t> uid)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)),
|
||||
uid_(std::move(uid)) {}
|
||||
|
||||
EnrichedLoginWindowSession(EnrichedLoginWindowSession &&) = default;
|
||||
|
||||
virtual ~EnrichedLoginWindowSession() = default;
|
||||
inline std::optional<uid_t> UID() const { return uid_; }
|
||||
|
||||
private:
|
||||
std::optional<uid_t> uid_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class EnrichedLoginWindowSessionLogin
|
||||
: public internal::EnrichedLoginWindowSession {
|
||||
using EnrichedLoginWindowSession::EnrichedLoginWindowSession;
|
||||
};
|
||||
|
||||
class EnrichedLoginWindowSessionLogout
|
||||
: public internal::EnrichedLoginWindowSession {
|
||||
using EnrichedLoginWindowSession::EnrichedLoginWindowSession;
|
||||
};
|
||||
|
||||
class EnrichedLoginWindowSessionLock
|
||||
: public internal::EnrichedLoginWindowSession {
|
||||
using EnrichedLoginWindowSession::EnrichedLoginWindowSession;
|
||||
};
|
||||
|
||||
class EnrichedLoginWindowSessionUnlock
|
||||
: public internal::EnrichedLoginWindowSession {
|
||||
using EnrichedLoginWindowSession::EnrichedLoginWindowSession;
|
||||
};
|
||||
|
||||
class EnrichedScreenSharingAttach : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedScreenSharingAttach(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedScreenSharingAttach(EnrichedScreenSharingAttach &&) = default;
|
||||
};
|
||||
|
||||
class EnrichedScreenSharingDetach : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedScreenSharingDetach(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedScreenSharingDetach(EnrichedScreenSharingDetach &&) = default;
|
||||
};
|
||||
|
||||
class EnrichedOpenSSHLogin : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedOpenSSHLogin(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedOpenSSHLogin(EnrichedOpenSSHLogin &&) = default;
|
||||
};
|
||||
|
||||
class EnrichedOpenSSHLogout : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedOpenSSHLogout(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedOpenSSHLogout(EnrichedOpenSSHLogout &&) = default;
|
||||
};
|
||||
|
||||
class EnrichedLoginLogin : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedLoginLogin(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedLoginLogin(EnrichedLoginLogin &&) = default;
|
||||
};
|
||||
|
||||
class EnrichedLoginLogout : public EnrichedEventType {
|
||||
public:
|
||||
EnrichedLoginLogout(Message &&es_msg, EnrichedProcess instigator)
|
||||
: EnrichedEventType(std::move(es_msg), std::move(instigator)) {}
|
||||
|
||||
EnrichedLoginLogout(EnrichedLoginLogout &&) = default;
|
||||
};
|
||||
|
||||
using EnrichedType = std::variant<
|
||||
EnrichedClose, EnrichedExchange, EnrichedExec, EnrichedExit, EnrichedFork,
|
||||
EnrichedLink, EnrichedRename, EnrichedUnlink, EnrichedCSInvalidated,
|
||||
EnrichedLoginWindowSessionLogin, EnrichedLoginWindowSessionLogout,
|
||||
EnrichedLoginWindowSessionLock, EnrichedLoginWindowSessionUnlock,
|
||||
EnrichedScreenSharingAttach, EnrichedScreenSharingDetach,
|
||||
EnrichedOpenSSHLogin, EnrichedOpenSSHLogout, EnrichedLoginLogin,
|
||||
EnrichedLoginLogout>;
|
||||
|
||||
class EnrichedMessage {
|
||||
public:
|
||||
@@ -355,6 +454,6 @@ class EnrichedMessage {
|
||||
EnrichedType msg_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
#define SANTA__SANTAD__EVENTPROVIDERS_ENDPOINTSECURITY_ENRICHER_H
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "Source/common/SantaCache.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EnrichedTypes.h"
|
||||
#include "Source/santad/ProcessTree/process_tree.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
enum class EnrichOptions {
|
||||
// Specifies default enricher operation.
|
||||
@@ -33,7 +34,8 @@ enum class EnrichOptions {
|
||||
|
||||
class Enricher {
|
||||
public:
|
||||
Enricher(std::shared_ptr<process_tree::ProcessTree> pt = nullptr);
|
||||
Enricher(
|
||||
std::shared_ptr<santa::santad::process_tree::ProcessTree> pt = nullptr);
|
||||
virtual ~Enricher() = default;
|
||||
virtual std::unique_ptr<EnrichedMessage> Enrich(Message &&msg);
|
||||
virtual EnrichedProcess Enrich(
|
||||
@@ -47,14 +49,19 @@ class Enricher {
|
||||
virtual std::optional<std::shared_ptr<std::string>> UsernameForGID(
|
||||
gid_t gid, EnrichOptions options = EnrichOptions::kDefault);
|
||||
|
||||
// This method does not chache. It should not be used on a hot path.
|
||||
virtual std::optional<uid_t> UIDForUsername(
|
||||
std::string_view username,
|
||||
EnrichOptions options = EnrichOptions::kDefault);
|
||||
|
||||
private:
|
||||
SantaCache<uid_t, std::optional<std::shared_ptr<std::string>>>
|
||||
username_cache_;
|
||||
SantaCache<gid_t, std::optional<std::shared_ptr<std::string>>>
|
||||
groupname_cache_;
|
||||
std::shared_ptr<process_tree::ProcessTree> process_tree_;
|
||||
std::shared_ptr<santa::santad::process_tree::ProcessTree> process_tree_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,13 +23,17 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#include "Source/common/SNTLogging.h"
|
||||
#include "Source/common/String.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EnrichedTypes.h"
|
||||
#include "Source/santad/ProcessTree/SNTEndpointSecurityAdapter.h"
|
||||
#include "Source/santad/ProcessTree/process_tree.h"
|
||||
#include "Source/santad/ProcessTree/process_tree_macos.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
using santa::StringTokenToStringView;
|
||||
|
||||
namespace santa {
|
||||
|
||||
Enricher::Enricher(std::shared_ptr<::santa::santad::process_tree::ProcessTree> pt)
|
||||
: username_cache_(256), groupname_cache_(256), process_tree_(std::move(pt)) {}
|
||||
@@ -81,6 +85,42 @@ std::unique_ptr<EnrichedMessage> Enricher::Enrich(Message &&es_msg) {
|
||||
case ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedCSInvalidated(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
#if HAVE_MACOS_13
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN:
|
||||
return std::make_unique<EnrichedMessage>(EnrichedLoginWindowSessionLogin(
|
||||
std::move(es_msg), Enrich(*es_msg->process),
|
||||
UIDForUsername(StringTokenToStringView(es_msg->event.lw_session_login->username))));
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT:
|
||||
return std::make_unique<EnrichedMessage>(EnrichedLoginWindowSessionLogout(
|
||||
std::move(es_msg), Enrich(*es_msg->process),
|
||||
UIDForUsername(StringTokenToStringView(es_msg->event.lw_session_logout->username))));
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK:
|
||||
return std::make_unique<EnrichedMessage>(EnrichedLoginWindowSessionLock(
|
||||
std::move(es_msg), Enrich(*es_msg->process),
|
||||
UIDForUsername(StringTokenToStringView(es_msg->event.lw_session_lock->username))));
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK:
|
||||
return std::make_unique<EnrichedMessage>(EnrichedLoginWindowSessionUnlock(
|
||||
std::move(es_msg), Enrich(*es_msg->process),
|
||||
UIDForUsername(StringTokenToStringView(es_msg->event.lw_session_unlock->username))));
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedScreenSharingAttach(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedScreenSharingDetach(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedOpenSSHLogin(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedOpenSSHLogout(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
case ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedLoginLogin(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
case ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT:
|
||||
return std::make_unique<EnrichedMessage>(
|
||||
EnrichedLoginLogout(std::move(es_msg), Enrich(*es_msg->process)));
|
||||
#endif
|
||||
default:
|
||||
// This is a programming error
|
||||
LOGE(@"Attempting to enrich an unhandled event type: %d", es_msg->event_type);
|
||||
@@ -94,9 +134,10 @@ EnrichedProcess Enricher::Enrich(const es_process_t &es_proc, EnrichOptions opti
|
||||
UsernameForUID(audit_token_to_ruid(es_proc.audit_token), options),
|
||||
UsernameForGID(audit_token_to_rgid(es_proc.audit_token), options),
|
||||
Enrich(*es_proc.executable, options),
|
||||
process_tree_ ? process_tree_->ExportAnnotations(
|
||||
process_tree::PidFromAuditToken(es_proc.audit_token))
|
||||
: std::nullopt);
|
||||
process_tree_
|
||||
? process_tree_->ExportAnnotations(
|
||||
santa::santad::process_tree::PidFromAuditToken(es_proc.audit_token))
|
||||
: std::nullopt);
|
||||
}
|
||||
|
||||
EnrichedFile Enricher::Enrich(const es_file_t &es_file, EnrichOptions options) {
|
||||
@@ -152,4 +193,14 @@ std::optional<std::shared_ptr<std::string>> Enricher::UsernameForGID(gid_t gid,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
std::optional<uid_t> Enricher::UIDForUsername(std::string_view username, EnrichOptions options) {
|
||||
if (options == EnrichOptions::kLocalOnly) {
|
||||
// If `kLocalOnly` option is set, do not attempt a lookup
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
struct passwd *pw = getpwnam(username.data());
|
||||
return pw ? std::make_optional(pw->pw_uid) : std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace santa
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "Source/common/TestUtils.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Enricher.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::Enricher;
|
||||
|
||||
@interface EnricherTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#import "Source/common/SNTCommonEnums.h"
|
||||
#include "Source/santad/ProcessTree/process_tree.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class EndpointSecurityAPI;
|
||||
class MessagePeer;
|
||||
@@ -41,11 +41,11 @@ class Message {
|
||||
Message(const Message& other);
|
||||
Message& operator=(const Message& other) = delete;
|
||||
|
||||
void SetProcessToken(process_tree::ProcessToken tok);
|
||||
void SetProcessToken(santa::santad::process_tree::ProcessToken tok);
|
||||
|
||||
// Operators to access underlying es_message_t
|
||||
const es_message_t* operator->() const { return es_msg_; }
|
||||
const es_message_t& operator*() const { return *es_msg_; }
|
||||
inline const es_message_t* operator->() const { return es_msg_; }
|
||||
inline const es_message_t& operator*() const { return *es_msg_; }
|
||||
|
||||
// Helper to get the API associated with this message.
|
||||
// Used for things like es_exec_arg_count.
|
||||
@@ -60,12 +60,12 @@ class Message {
|
||||
inline StatChangeStep StatChangeStep() const { return stat_change_step_; }
|
||||
inline StatResult StatResult() const { return stat_result_; }
|
||||
|
||||
friend class santa::santad::event_providers::endpoint_security::MessagePeer;
|
||||
friend class santa::MessagePeer;
|
||||
|
||||
private:
|
||||
std::shared_ptr<EndpointSecurityAPI> esapi_;
|
||||
const es_message_t* es_msg_;
|
||||
std::optional<process_tree::ProcessToken> process_token_;
|
||||
std::optional<santa::santad::process_tree::ProcessToken> process_token_;
|
||||
|
||||
std::string GetProcessName(pid_t pid) const;
|
||||
|
||||
@@ -73,6 +73,6 @@ class Message {
|
||||
mutable enum StatResult stat_result_ = StatResult::kOK;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
|
||||
|
||||
namespace santa::santad::event_providers::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
Message::Message(std::shared_ptr<EndpointSecurityAPI> esapi, const es_message_t *es_msg)
|
||||
: esapi_(std::move(esapi)), es_msg_(es_msg), process_token_(std::nullopt) {
|
||||
@@ -72,7 +72,7 @@ void Message::UpdateStatState(enum StatChangeStep step) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Message::SetProcessToken(process_tree::ProcessToken tok) {
|
||||
void Message::SetProcessToken(santa::santad::process_tree::ProcessToken tok) {
|
||||
process_token_ = std::move(tok);
|
||||
}
|
||||
|
||||
@@ -91,4 +91,4 @@ std::string Message::GetProcessName(pid_t pid) const {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace santa::santad::event_providers::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/MockEndpointSecurityAPI.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::Message;
|
||||
|
||||
bool IsPidInUse(pid_t pid) {
|
||||
char pname[MAXCOMLEN * 2 + 1] = {};
|
||||
|
||||
@@ -27,18 +27,13 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::Client;
|
||||
|
||||
class MockEndpointSecurityAPI
|
||||
: public santa::santad::event_providers::endpoint_security::EndpointSecurityAPI {
|
||||
class MockEndpointSecurityAPI : public santa::EndpointSecurityAPI {
|
||||
public:
|
||||
MOCK_METHOD(santa::santad::event_providers::endpoint_security::Client, NewClient,
|
||||
(void (^message_handler)(
|
||||
es_client_t *, santa::santad::event_providers::endpoint_security::Message)));
|
||||
MOCK_METHOD(santa::Client, NewClient, (void (^message_handler)(es_client_t *, santa::Message)));
|
||||
|
||||
MOCK_METHOD(bool, Subscribe,
|
||||
(const santa::santad::event_providers::endpoint_security::Client &,
|
||||
const std::set<es_event_type_t> &));
|
||||
MOCK_METHOD(bool, Subscribe, (const santa::Client &, const std::set<es_event_type_t> &));
|
||||
MOCK_METHOD(bool, UnsubscribeAll, (const Client &client));
|
||||
|
||||
MOCK_METHOD(bool, UnmuteAllPaths, (const Client &client));
|
||||
@@ -48,30 +43,23 @@ class MockEndpointSecurityAPI
|
||||
MOCK_METHOD(bool, InvertTargetPathMuting, (const Client &client));
|
||||
|
||||
MOCK_METHOD(bool, MuteTargetPath,
|
||||
(const Client &client, std::string_view path,
|
||||
santa::santad::data_layer::WatchItemPathType path_type));
|
||||
(const Client &client, std::string_view path, santa::WatchItemPathType path_type));
|
||||
MOCK_METHOD(bool, UnmuteTargetPath,
|
||||
(const Client &client, std::string_view path,
|
||||
santa::santad::data_layer::WatchItemPathType path_type));
|
||||
(const Client &client, std::string_view path, santa::WatchItemPathType path_type));
|
||||
|
||||
MOCK_METHOD(void, RetainMessage, (const es_message_t *msg));
|
||||
MOCK_METHOD(void, ReleaseMessage, (const es_message_t *msg));
|
||||
|
||||
MOCK_METHOD(bool, RespondAuthResult,
|
||||
(const santa::santad::event_providers::endpoint_security::Client &,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
es_auth_result_t result, bool cache));
|
||||
(const santa::Client &, const santa::Message &msg, es_auth_result_t result,
|
||||
bool cache));
|
||||
MOCK_METHOD(bool, RespondFlagsResult,
|
||||
(const santa::santad::event_providers::endpoint_security::Client &client,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
uint32_t allowed_flags, bool cache));
|
||||
(const santa::Client &client, const santa::Message &msg, uint32_t allowed_flags,
|
||||
bool cache));
|
||||
|
||||
MOCK_METHOD(bool, MuteProcess,
|
||||
(const santa::santad::event_providers::endpoint_security::Client &,
|
||||
const audit_token_t *tok));
|
||||
MOCK_METHOD(bool, MuteProcess, (const santa::Client &, const audit_token_t *tok));
|
||||
|
||||
MOCK_METHOD(bool, ClearCache,
|
||||
(const santa::santad::event_providers::endpoint_security::Client &));
|
||||
MOCK_METHOD(bool, ClearCache, (const santa::Client &));
|
||||
|
||||
MOCK_METHOD(uint32_t, ExecArgCount, (const es_event_exec_t *event));
|
||||
MOCK_METHOD(es_string_token_t, ExecArg, (const es_event_exec_t *event, uint32_t index));
|
||||
@@ -84,8 +72,7 @@ class MockEndpointSecurityAPI
|
||||
|
||||
void SetExpectationsESNewClient() {
|
||||
EXPECT_CALL(*this, NewClient)
|
||||
.WillOnce(testing::Return(santa::santad::event_providers::endpoint_security::Client(
|
||||
nullptr, ES_NEW_CLIENT_RESULT_SUCCESS)));
|
||||
.WillOnce(testing::Return(santa::Client(nullptr, ES_NEW_CLIENT_RESULT_SUCCESS)));
|
||||
EXPECT_CALL(*this, MuteProcess).WillOnce(testing::Return(true));
|
||||
EXPECT_CALL(*this, ClearCache).WillRepeatedly(testing::Return(true));
|
||||
EXPECT_CALL(*this, Subscribe).WillRepeatedly(testing::Return(true));
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
class RateLimiterPeer;
|
||||
}
|
||||
} // namespace santa
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
|
||||
// Very basic rate limiting infrastructure.
|
||||
// Currently only handles X events per duration.
|
||||
@@ -39,12 +39,11 @@ class RateLimiter {
|
||||
public:
|
||||
// Factory
|
||||
static std::shared_ptr<RateLimiter> Create(
|
||||
std::shared_ptr<santa::santad::Metrics> metrics,
|
||||
santa::santad::Processor processor, uint16_t max_qps,
|
||||
NSTimeInterval reset_duration = kDefaultResetDuration);
|
||||
std::shared_ptr<santa::Metrics> metrics, santa::Processor processor,
|
||||
uint16_t max_qps, NSTimeInterval reset_duration = kDefaultResetDuration);
|
||||
|
||||
RateLimiter(std::shared_ptr<santa::santad::Metrics> metrics,
|
||||
santa::santad::Processor processor, uint16_t max_qps,
|
||||
RateLimiter(std::shared_ptr<santa::Metrics> metrics,
|
||||
santa::Processor processor, uint16_t max_qps,
|
||||
NSTimeInterval reset_duration);
|
||||
|
||||
enum class Decision {
|
||||
@@ -54,7 +53,7 @@ class RateLimiter {
|
||||
|
||||
Decision Decide(uint64_t cur_mach_time);
|
||||
|
||||
friend class santa::santad::event_providers::RateLimiterPeer;
|
||||
friend class santa::RateLimiterPeer;
|
||||
|
||||
private:
|
||||
bool ShouldRateLimitLocked();
|
||||
@@ -63,8 +62,8 @@ class RateLimiter {
|
||||
|
||||
static constexpr NSTimeInterval kDefaultResetDuration = 15.0;
|
||||
|
||||
std::shared_ptr<santa::santad::Metrics> metrics_;
|
||||
santa::santad::Processor processor_;
|
||||
std::shared_ptr<santa::Metrics> metrics_;
|
||||
santa::Processor processor_;
|
||||
size_t log_count_total_ = 0;
|
||||
size_t max_log_count_total_;
|
||||
uint64_t reset_mach_time_;
|
||||
@@ -72,6 +71,6 @@ class RateLimiter {
|
||||
dispatch_queue_t q_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
#include "Source/common/BranchPrediction.h"
|
||||
#include "Source/common/SystemResources.h"
|
||||
|
||||
using santa::santad::Metrics;
|
||||
using santa::santad::Processor;
|
||||
using santa::Metrics;
|
||||
using santa::Processor;
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
|
||||
std::shared_ptr<RateLimiter> RateLimiter::Create(std::shared_ptr<Metrics> metrics,
|
||||
Processor processor, uint16_t max_qps,
|
||||
@@ -82,4 +82,4 @@ RateLimiter::Decision RateLimiter::Decide(uint64_t cur_mach_time) {
|
||||
return decision;
|
||||
}
|
||||
|
||||
} // namespace santa::santad::event_providers
|
||||
} // namespace santa
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
#include "Source/common/SystemResources.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::event_providers::RateLimiter;
|
||||
using santa::RateLimiter;
|
||||
|
||||
static const santa::santad::Processor kDefaultProcessor =
|
||||
santa::santad::Processor::kFileAccessAuthorizer;
|
||||
static const santa::Processor kDefaultProcessor = santa::Processor::kFileAccessAuthorizer;
|
||||
|
||||
namespace santa::santad::event_providers {
|
||||
namespace santa {
|
||||
|
||||
class RateLimiterPeer : public RateLimiter {
|
||||
public:
|
||||
@@ -39,9 +38,9 @@ class RateLimiterPeer : public RateLimiter {
|
||||
using RateLimiter::reset_mach_time_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::event_providers
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::event_providers::RateLimiterPeer;
|
||||
using santa::RateLimiterPeer;
|
||||
|
||||
@interface RateLimiterTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -27,14 +27,10 @@
|
||||
@interface SNTEndpointSecurityAuthorizer
|
||||
: SNTEndpointSecurityClient <SNTEndpointSecurityEventHandler>
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)
|
||||
esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
execController:(SNTExecutionController *)execController
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
authResultCache:
|
||||
(std::shared_ptr<santa::santad::event_providers::AuthResultCache>)authResultCache;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
execController:(SNTExecutionController *)execController
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
authResultCache:(std::shared_ptr<santa::AuthResultCache>)authResultCache;
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EventDisposition;
|
||||
using santa::Message;
|
||||
|
||||
@interface SNTEndpointSecurityAuthorizer ()
|
||||
@property SNTCompilerController *compilerController;
|
||||
@@ -41,13 +41,13 @@ using santa::santad::event_providers::endpoint_security::Message;
|
||||
}
|
||||
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
execController:(SNTExecutionController *)execController
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
authResultCache:(std::shared_ptr<AuthResultCache>)authResultCache {
|
||||
self = [super initWithESAPI:std::move(esApi)
|
||||
metrics:std::move(metrics)
|
||||
processor:santa::santad::Processor::kAuthorizer];
|
||||
processor:santa::Processor::kAuthorizer];
|
||||
if (self) {
|
||||
_execController = execController;
|
||||
_compilerController = compilerController;
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
#import "Source/santad/SNTCompilerController.h"
|
||||
#import "Source/santad/SNTExecutionController.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EventDisposition;
|
||||
using santa::Message;
|
||||
|
||||
class MockAuthResultCache : public AuthResultCache {
|
||||
public:
|
||||
@@ -72,7 +72,7 @@ class MockAuthResultCache : public AuthResultCache {
|
||||
id authClient =
|
||||
[[SNTEndpointSecurityAuthorizer alloc] initWithESAPI:mockESApi
|
||||
metrics:nullptr
|
||||
processor:santa::santad::Processor::kAuthorizer];
|
||||
processor:santa::Processor::kAuthorizer];
|
||||
|
||||
EXPECT_CALL(*mockESApi, ClearCache)
|
||||
.After(EXPECT_CALL(*mockESApi, Subscribe(testing::_, expectedEventSubs))
|
||||
@@ -81,6 +81,10 @@ class MockAuthResultCache : public AuthResultCache {
|
||||
|
||||
[authClient enable];
|
||||
|
||||
for (const auto &event : expectedEventSubs) {
|
||||
XCTAssertNoThrow(santa::EventTypeToString(event));
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::Metrics;
|
||||
using santa::santad::Processor;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::Client;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::EventDisposition;
|
||||
using santa::Message;
|
||||
using santa::Metrics;
|
||||
using santa::Processor;
|
||||
using santa::WatchItemPathType;
|
||||
|
||||
constexpr std::string_view kProtectedFiles[] = {"/private/var/db/santa/rules.db",
|
||||
"/private/var/db/santa/events.db"};
|
||||
|
||||
@@ -29,11 +29,9 @@
|
||||
|
||||
@protocol SNTEndpointSecurityClientBase
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
processor:(santa::santad::Processor)processor;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
processor:(santa::Processor)processor;
|
||||
|
||||
/// @note If this fails to establish a new ES client via `es_new_client`, an exception is raised
|
||||
/// that should terminate the program.
|
||||
@@ -52,9 +50,9 @@
|
||||
- (bool)unmuteAllTargetPaths;
|
||||
- (bool)enableTargetPathWatching;
|
||||
- (bool)muteTargetPaths:
|
||||
(const std::vector<std::pair<std::string, santa::santad::data_layer::WatchItemPathType>> &)paths;
|
||||
(const std::vector<std::pair<std::string, santa::WatchItemPathType>> &)paths;
|
||||
- (bool)unmuteTargetPaths:
|
||||
(const std::vector<std::pair<std::string, santa::santad::data_layer::WatchItemPathType>> &)paths;
|
||||
(const std::vector<std::pair<std::string, santa::WatchItemPathType>> &)paths;
|
||||
|
||||
/// Responds to the Message with the given auth result
|
||||
///
|
||||
@@ -66,27 +64,18 @@
|
||||
/// @note If the msg event type requires a flags response, the correct ES API will automatically
|
||||
/// be called. ALLOWED results will be translated to having all flags set, and DENIED results
|
||||
/// will be translated to having all flags cleared.
|
||||
- (bool)respondToMessage:(const santa::santad::event_providers::endpoint_security::Message &)msg
|
||||
- (bool)respondToMessage:(const santa::Message &)msg
|
||||
withAuthResult:(es_auth_result_t)result
|
||||
cacheable:(bool)cacheable;
|
||||
|
||||
- (void)
|
||||
processEnrichedMessage:
|
||||
(std::unique_ptr<santa::santad::event_providers::endpoint_security::EnrichedMessage>)msg
|
||||
handler:
|
||||
(void (^)(std::unique_ptr<
|
||||
santa::santad::event_providers::endpoint_security::EnrichedMessage>))
|
||||
messageHandler;
|
||||
- (void)processEnrichedMessage:(std::unique_ptr<santa::EnrichedMessage>)msg
|
||||
handler:(void (^)(std::unique_ptr<santa::EnrichedMessage>))messageHandler;
|
||||
|
||||
- (void)asynchronouslyProcess:(santa::santad::event_providers::endpoint_security::Message)msg
|
||||
handler:
|
||||
(void (^)(santa::santad::event_providers::endpoint_security::Message &&))
|
||||
messageHandler;
|
||||
- (void)asynchronouslyProcess:(santa::Message)msg
|
||||
handler:(void (^)(santa::Message &&))messageHandler;
|
||||
|
||||
- (void)processMessage:(santa::santad::event_providers::endpoint_security::Message &&)msg
|
||||
handler:
|
||||
(void (^)(const santa::santad::event_providers::endpoint_security::Message &))
|
||||
messageHandler;
|
||||
- (void)processMessage:(santa::Message &&)msg
|
||||
handler:(void (^)(const santa::Message &))messageHandler;
|
||||
|
||||
- (bool)clearCache;
|
||||
|
||||
|
||||
@@ -34,21 +34,21 @@
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityClient.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::Processor;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedClose;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFile;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::Client;
|
||||
using santa::EnrichedClose;
|
||||
using santa::EnrichedFile;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::Message;
|
||||
using santa::Processor;
|
||||
using santa::WatchItemPathType;
|
||||
|
||||
@interface SNTEndpointSecurityClient (Testing)
|
||||
- (void)establishClientOrDie;
|
||||
- (bool)muteSelf;
|
||||
- (NSString *)errorMessageForNewClientResult:(es_new_client_result_t)result;
|
||||
- (void)handleMessage:(Message &&)esMsg
|
||||
recordEventMetrics:(void (^)(santa::santad::EventDisposition disposition))recordEventMetrics;
|
||||
recordEventMetrics:(void (^)(santa::EventDisposition disposition))recordEventMetrics;
|
||||
- (BOOL)shouldHandleMessage:(const Message &)esMsg;
|
||||
- (int64_t)computeBudgetForDeadline:(uint64_t)deadline currentTime:(uint64_t)currentTime;
|
||||
|
||||
|
||||
@@ -39,17 +39,13 @@ typedef void (^SNTDeviceBlockCallback)(SNTDeviceEvent *event);
|
||||
@property(nonatomic, readwrite, nullable) NSArray<NSString *> *remountArgs;
|
||||
@property(nonatomic, nullable) SNTDeviceBlockCallback deviceBlockCallback;
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)
|
||||
esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::santad::logs::endpoint_security::Logger>)logger
|
||||
authResultCache:
|
||||
(std::shared_ptr<santa::santad::event_providers::AuthResultCache>)authResultCache
|
||||
blockUSBMount:(BOOL)blockUSBMount
|
||||
remountUSBMode:(nullable NSArray<NSString *> *)remountUSBMode
|
||||
startupPreferences:(SNTDeviceManagerStartupPreferences)startupPrefs;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::Logger>)logger
|
||||
authResultCache:(std::shared_ptr<santa::AuthResultCache>)authResultCache
|
||||
blockUSBMount:(BOOL)blockUSBMount
|
||||
remountUSBMode:(nullable NSArray<NSString *> *)remountUSBMode
|
||||
startupPreferences:(SNTDeviceManagerStartupPreferences)startupPrefs;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::FlushCacheMode;
|
||||
using santa::santad::event_providers::FlushCacheReason;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EventDisposition;
|
||||
using santa::FlushCacheMode;
|
||||
using santa::FlushCacheReason;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
|
||||
// Defined operations for startup metrics:
|
||||
// Device shouldn't be operated on (e.g. not a mass storage device)
|
||||
@@ -178,7 +178,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<Logger>)logger
|
||||
authResultCache:(std::shared_ptr<AuthResultCache>)authResultCache
|
||||
blockUSBMount:(BOOL)blockUSBMount
|
||||
@@ -186,7 +186,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
startupPreferences:(SNTDeviceManagerStartupPreferences)startupPrefs {
|
||||
self = [super initWithESAPI:std::move(esApi)
|
||||
metrics:std::move(metrics)
|
||||
processor:santa::santad::Processor::kDeviceManager];
|
||||
processor:santa::Processor::kDeviceManager];
|
||||
if (self) {
|
||||
_logger = logger;
|
||||
_authResultCache = authResultCache;
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityDeviceManager.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::FlushCacheMode;
|
||||
using santa::santad::event_providers::FlushCacheReason;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EventDisposition;
|
||||
using santa::FlushCacheMode;
|
||||
using santa::FlushCacheReason;
|
||||
using santa::Message;
|
||||
|
||||
class MockAuthResultCache : public AuthResultCache {
|
||||
public:
|
||||
@@ -384,18 +384,21 @@ class MockAuthResultCache : public AuthResultCache {
|
||||
on:@"v2"
|
||||
flags:@(MNT_RDONLY | MNT_NOEXEC | MNT_JOURNALED)]];
|
||||
|
||||
// Disabling clang format due to local/remote version differences.
|
||||
// clang-format off
|
||||
// Create mock disks with desired args
|
||||
MockDADisk * (^CreateMockDisk)(NSString *, NSString *) =
|
||||
^MockDADisk *(NSString *mountOn, NSString *mountFrom) {
|
||||
MockDADisk *mockDisk = [[MockDADisk alloc] init];
|
||||
mockDisk.diskDescription = @{
|
||||
@"DAVolumePath" : mountOn, // f_mntonname,
|
||||
@"DADevicePath" : mountOn, // f_mntonname,
|
||||
@"DAMediaBSDName" : mountFrom, // f_mntfromname,
|
||||
};
|
||||
MockDADisk *mockDisk = [[MockDADisk alloc] init];
|
||||
mockDisk.diskDescription = @{
|
||||
@"DAVolumePath" : mountOn, // f_mntonname,
|
||||
@"DADevicePath" : mountOn, // f_mntonname,
|
||||
@"DAMediaBSDName" : mountFrom, // f_mntfromname,
|
||||
};
|
||||
|
||||
return mockDisk;
|
||||
};
|
||||
return mockDisk;
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Reset the Mock DA property, setup disks and remount args, then trigger the test
|
||||
void (^PerformStartupTest)(NSArray<MockDADisk *> *, NSArray<NSString *> *,
|
||||
@@ -495,10 +498,10 @@ class MockAuthResultCache : public AuthResultCache {
|
||||
};
|
||||
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
|
||||
id deviceClient = [[SNTEndpointSecurityDeviceManager alloc]
|
||||
initWithESAPI:mockESApi
|
||||
metrics:nullptr
|
||||
processor:santa::santad::Processor::kDeviceManager];
|
||||
id deviceClient =
|
||||
[[SNTEndpointSecurityDeviceManager alloc] initWithESAPI:mockESApi
|
||||
metrics:nullptr
|
||||
processor:santa::Processor::kDeviceManager];
|
||||
|
||||
EXPECT_CALL(*mockESApi, ClearCache(testing::_))
|
||||
.After(EXPECT_CALL(*mockESApi, Subscribe(testing::_, expectedEventSubs))
|
||||
@@ -507,6 +510,10 @@ class MockAuthResultCache : public AuthResultCache {
|
||||
|
||||
[deviceClient enable];
|
||||
|
||||
for (const auto &event : expectedEventSubs) {
|
||||
XCTAssertNoThrow(santa::EventTypeToString(event));
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
// Called Synchronously and serially for each message provided by the
|
||||
// EndpointSecurity framework.
|
||||
- (void)handleMessage:(santa::santad::event_providers::endpoint_security::Message &&)esMsg
|
||||
recordEventMetrics:(void (^)(santa::santad::EventDisposition))recordEventMetrics;
|
||||
- (void)handleMessage:(santa::Message &&)esMsg
|
||||
recordEventMetrics:(void (^)(santa::EventDisposition))recordEventMetrics;
|
||||
|
||||
// Called after Santa has finished initializing itself.
|
||||
// This is an optimal place to subscribe to ES events
|
||||
@@ -43,13 +43,10 @@
|
||||
// Called when a client should no longer receive events.
|
||||
- (void)disable;
|
||||
|
||||
- (void)
|
||||
watchItemsCount:(size_t)count
|
||||
newPaths:
|
||||
(const std::vector<std::pair<std::string, santa::santad::data_layer::WatchItemPathType>>
|
||||
&)newPaths
|
||||
removedPaths:
|
||||
(const std::vector<std::pair<std::string, santa::santad::data_layer::WatchItemPathType>> &)
|
||||
removedPaths;
|
||||
- (void)watchItemsCount:(size_t)count
|
||||
newPaths:
|
||||
(const std::vector<std::pair<std::string, santa::WatchItemPathType>> &)newPaths
|
||||
removedPaths:
|
||||
(const std::vector<std::pair<std::string, santa::WatchItemPathType>> &)removedPaths;
|
||||
|
||||
@end
|
||||
|
||||
@@ -33,16 +33,13 @@ typedef void (^SNTFileAccessBlockCallback)(SNTFileAccessEvent *event, NSString *
|
||||
@interface SNTEndpointSecurityFileAccessAuthorizer
|
||||
: SNTEndpointSecurityClient <SNTEndpointSecurityDynamicEventHandler>
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::santad::logs::endpoint_security::Logger>)logger
|
||||
watchItems:(std::shared_ptr<santa::santad::data_layer::WatchItems>)watchItems
|
||||
enricher:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::Enricher>)enricher
|
||||
decisionCache:(SNTDecisionCache *)decisionCache
|
||||
ttyWriter:(std::shared_ptr<santa::santad::TTYWriter>)ttyWriter;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::Logger>)logger
|
||||
watchItems:(std::shared_ptr<santa::WatchItems>)watchItems
|
||||
enricher:(std::shared_ptr<santa::Enricher>)enricher
|
||||
decisionCache:(SNTDecisionCache *)decisionCache
|
||||
ttyWriter:(std::shared_ptr<santa::TTYWriter>)ttyWriter;
|
||||
|
||||
@property SNTFileAccessBlockCallback fileAccessBlockCallback;
|
||||
|
||||
|
||||
@@ -51,21 +51,21 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
|
||||
using santa::common::OptionalStringToNSString;
|
||||
using santa::common::StringToNSString;
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::FileAccessMetricStatus;
|
||||
using santa::santad::Metrics;
|
||||
using santa::santad::TTYWriter;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::data_layer::WatchItemPolicy;
|
||||
using santa::santad::data_layer::WatchItems;
|
||||
using santa::santad::event_providers::RateLimiter;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichOptions;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::Enricher;
|
||||
using santa::EnrichOptions;
|
||||
using santa::EventDisposition;
|
||||
using santa::FileAccessMetricStatus;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
using santa::Metrics;
|
||||
using santa::OptionalStringToNSString;
|
||||
using santa::RateLimiter;
|
||||
using santa::StringToNSString;
|
||||
using santa::TTYWriter;
|
||||
using santa::WatchItemPathType;
|
||||
using santa::WatchItemPolicy;
|
||||
using santa::WatchItems;
|
||||
|
||||
NSString *kBadCertHash = @"BAD_CERT_HASH";
|
||||
|
||||
@@ -396,19 +396,16 @@ bool ShouldMessageTTY(const std::shared_ptr<WatchItemPolicy> &policy, const Mess
|
||||
std::shared_ptr<Metrics> _metrics;
|
||||
}
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::santad::logs::endpoint_security::Logger>)logger
|
||||
watchItems:(std::shared_ptr<WatchItems>)watchItems
|
||||
enricher:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::Enricher>)enricher
|
||||
decisionCache:(SNTDecisionCache *)decisionCache
|
||||
ttyWriter:(std::shared_ptr<santa::santad::TTYWriter>)ttyWriter {
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::Logger>)logger
|
||||
watchItems:(std::shared_ptr<WatchItems>)watchItems
|
||||
enricher:(std::shared_ptr<santa::Enricher>)enricher
|
||||
decisionCache:(SNTDecisionCache *)decisionCache
|
||||
ttyWriter:(std::shared_ptr<santa::TTYWriter>)ttyWriter {
|
||||
self = [super initWithESAPI:std::move(esApi)
|
||||
metrics:metrics
|
||||
processor:santa::santad::Processor::kFileAccessAuthorizer];
|
||||
processor:santa::Processor::kFileAccessAuthorizer];
|
||||
if (self) {
|
||||
_watchItems = std::move(watchItems);
|
||||
_logger = std::move(logger);
|
||||
@@ -419,8 +416,8 @@ bool ShouldMessageTTY(const std::shared_ptr<WatchItemPolicy> &policy, const Mess
|
||||
|
||||
_configurator = [SNTConfigurator configurator];
|
||||
|
||||
_rateLimiter = RateLimiter::Create(_metrics, santa::santad::Processor::kFileAccessAuthorizer,
|
||||
kDefaultRateLimitQPS);
|
||||
_rateLimiter =
|
||||
RateLimiter::Create(_metrics, santa::Processor::kFileAccessAuthorizer, kDefaultRateLimitQPS);
|
||||
|
||||
SNTMetricBooleanGauge *famEnabled = [[SNTMetricSet sharedInstance]
|
||||
booleanGaugeWithName:@"/santa/fam_enabled"
|
||||
@@ -797,7 +794,7 @@ bool ShouldMessageTTY(const std::shared_ptr<WatchItemPolicy> &policy, const Mess
|
||||
cacheable:(policyResult == ES_AUTH_RESULT_ALLOW && !allow_read_access)];
|
||||
}
|
||||
|
||||
- (void)handleMessage:(santa::santad::event_providers::endpoint_security::Message &&)esMsg
|
||||
- (void)handleMessage:(santa::Message &&)esMsg
|
||||
recordEventMetrics:(void (^)(EventDisposition))recordEventMetrics {
|
||||
SNTOverrideFileAccessAction overrideAction = [self.configurator overrideFileAccessAction];
|
||||
|
||||
@@ -834,17 +831,12 @@ bool ShouldMessageTTY(const std::shared_ptr<WatchItemPolicy> &policy, const Mess
|
||||
|
||||
- (void)enable {
|
||||
std::set<es_event_type_t> events = {
|
||||
ES_EVENT_TYPE_AUTH_CLONE, ES_EVENT_TYPE_AUTH_CREATE, ES_EVENT_TYPE_AUTH_EXCHANGEDATA,
|
||||
ES_EVENT_TYPE_AUTH_LINK, ES_EVENT_TYPE_AUTH_OPEN, ES_EVENT_TYPE_AUTH_RENAME,
|
||||
ES_EVENT_TYPE_AUTH_TRUNCATE, ES_EVENT_TYPE_AUTH_UNLINK, ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
ES_EVENT_TYPE_AUTH_CLONE, ES_EVENT_TYPE_AUTH_COPYFILE, ES_EVENT_TYPE_AUTH_CREATE,
|
||||
ES_EVENT_TYPE_AUTH_EXCHANGEDATA, ES_EVENT_TYPE_AUTH_LINK, ES_EVENT_TYPE_AUTH_OPEN,
|
||||
ES_EVENT_TYPE_AUTH_RENAME, ES_EVENT_TYPE_AUTH_TRUNCATE, ES_EVENT_TYPE_AUTH_UNLINK,
|
||||
ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
};
|
||||
|
||||
#if HAVE_MACOS_12
|
||||
if (@available(macOS 12.0, *)) {
|
||||
events.insert(ES_EVENT_TYPE_AUTH_COPYFILE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!self.isSubscribed) {
|
||||
if ([super subscribe:events]) {
|
||||
self.isSubscribed = true;
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
#include "Source/santad/Logs/EndpointSecurity/MockLogger.h"
|
||||
#include "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
using santa::santad::data_layer::WatchItemPolicy;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::Message;
|
||||
using santa::WatchItemPolicy;
|
||||
|
||||
extern NSString *kBadCertHash;
|
||||
|
||||
@@ -729,17 +729,12 @@ void ClearWatchItemPolicyProcess(WatchItemPolicy::Process &proc) {
|
||||
|
||||
- (void)testEnable {
|
||||
std::set<es_event_type_t> expectedEventSubs = {
|
||||
ES_EVENT_TYPE_AUTH_CLONE, ES_EVENT_TYPE_AUTH_CREATE, ES_EVENT_TYPE_AUTH_EXCHANGEDATA,
|
||||
ES_EVENT_TYPE_AUTH_LINK, ES_EVENT_TYPE_AUTH_OPEN, ES_EVENT_TYPE_AUTH_RENAME,
|
||||
ES_EVENT_TYPE_AUTH_TRUNCATE, ES_EVENT_TYPE_AUTH_UNLINK, ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
ES_EVENT_TYPE_AUTH_CLONE, ES_EVENT_TYPE_AUTH_COPYFILE, ES_EVENT_TYPE_AUTH_CREATE,
|
||||
ES_EVENT_TYPE_AUTH_EXCHANGEDATA, ES_EVENT_TYPE_AUTH_LINK, ES_EVENT_TYPE_AUTH_OPEN,
|
||||
ES_EVENT_TYPE_AUTH_RENAME, ES_EVENT_TYPE_AUTH_TRUNCATE, ES_EVENT_TYPE_AUTH_UNLINK,
|
||||
ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
};
|
||||
|
||||
#if HAVE_MACOS_12
|
||||
if (@available(macOS 12.0, *)) {
|
||||
expectedEventSubs.insert(ES_EVENT_TYPE_AUTH_COPYFILE);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
EXPECT_CALL(*mockESApi, ClearCache)
|
||||
.After(EXPECT_CALL(*mockESApi, Subscribe(testing::_, expectedEventSubs))
|
||||
@@ -749,10 +744,14 @@ void ClearWatchItemPolicyProcess(WatchItemPolicy::Process &proc) {
|
||||
id fileAccessClient = [[SNTEndpointSecurityFileAccessAuthorizer alloc]
|
||||
initWithESAPI:mockESApi
|
||||
metrics:nullptr
|
||||
processor:santa::santad::Processor::kFileAccessAuthorizer];
|
||||
processor:santa::Processor::kFileAccessAuthorizer];
|
||||
|
||||
[fileAccessClient enable];
|
||||
|
||||
for (const auto &event : expectedEventSubs) {
|
||||
XCTAssertNoThrow(santa::EventTypeToString(event));
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
}
|
||||
|
||||
@@ -940,42 +939,40 @@ void ClearWatchItemPolicyProcess(WatchItemPolicy::Process &proc) {
|
||||
XCTAssertFalse(targets[0].devnoIno.has_value());
|
||||
}
|
||||
|
||||
if (@available(macOS 12.0, *)) {
|
||||
{
|
||||
esMsg.event_type = ES_EVENT_TYPE_AUTH_COPYFILE;
|
||||
esMsg.event.copyfile.source = &testFile1;
|
||||
esMsg.event.copyfile.target_dir = &testDir;
|
||||
esMsg.event.copyfile.target_name = testTok;
|
||||
|
||||
{
|
||||
esMsg.event_type = ES_EVENT_TYPE_AUTH_COPYFILE;
|
||||
esMsg.event.copyfile.source = &testFile1;
|
||||
esMsg.event.copyfile.target_dir = &testDir;
|
||||
esMsg.event.copyfile.target_name = testTok;
|
||||
esMsg.event.copyfile.target_file = nullptr;
|
||||
|
||||
{
|
||||
esMsg.event.copyfile.target_file = nullptr;
|
||||
std::vector<PathTarget> targets;
|
||||
PopulatePathTargets(msg, targets);
|
||||
|
||||
std::vector<PathTarget> targets;
|
||||
PopulatePathTargets(msg, targets);
|
||||
XCTAssertEqual(targets.size(), 2);
|
||||
XCTAssertCStringEqual(targets[0].path.c_str(), testFile1.path.data);
|
||||
XCTAssertTrue(targets[0].isReadable);
|
||||
XCTAssertEqual(targets[0].devnoIno.value(), FileID(testFile1));
|
||||
XCTAssertCppStringEqual(targets[1].path, dirTok);
|
||||
XCTAssertFalse(targets[1].isReadable);
|
||||
XCTAssertFalse(targets[1].devnoIno.has_value());
|
||||
}
|
||||
|
||||
XCTAssertEqual(targets.size(), 2);
|
||||
XCTAssertCStringEqual(targets[0].path.c_str(), testFile1.path.data);
|
||||
XCTAssertTrue(targets[0].isReadable);
|
||||
XCTAssertEqual(targets[0].devnoIno.value(), FileID(testFile1));
|
||||
XCTAssertCppStringEqual(targets[1].path, dirTok);
|
||||
XCTAssertFalse(targets[1].isReadable);
|
||||
XCTAssertFalse(targets[1].devnoIno.has_value());
|
||||
}
|
||||
{
|
||||
esMsg.event.copyfile.target_file = &testFile2;
|
||||
|
||||
{
|
||||
esMsg.event.copyfile.target_file = &testFile2;
|
||||
std::vector<PathTarget> targets;
|
||||
PopulatePathTargets(msg, targets);
|
||||
|
||||
std::vector<PathTarget> targets;
|
||||
PopulatePathTargets(msg, targets);
|
||||
|
||||
XCTAssertEqual(targets.size(), 2);
|
||||
XCTAssertCStringEqual(targets[0].path.c_str(), testFile1.path.data);
|
||||
XCTAssertTrue(targets[0].isReadable);
|
||||
XCTAssertEqual(targets[0].devnoIno.value(), FileID(testFile1));
|
||||
XCTAssertCStringEqual(targets[1].path.c_str(), testFile2.path.data);
|
||||
XCTAssertFalse(targets[1].isReadable);
|
||||
XCTAssertFalse(targets[1].devnoIno.has_value());
|
||||
}
|
||||
XCTAssertEqual(targets.size(), 2);
|
||||
XCTAssertCStringEqual(targets[0].path.c_str(), testFile1.path.data);
|
||||
XCTAssertTrue(targets[0].isReadable);
|
||||
XCTAssertEqual(targets[0].devnoIno.value(), FileID(testFile1));
|
||||
XCTAssertCStringEqual(targets[1].path.c_str(), testFile2.path.data);
|
||||
XCTAssertFalse(targets[1].isReadable);
|
||||
XCTAssertFalse(targets[1].devnoIno.has_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,18 +29,14 @@
|
||||
@interface SNTEndpointSecurityRecorder
|
||||
: SNTEndpointSecurityTreeAwareClient <SNTEndpointSecurityEventHandler>
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)
|
||||
esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::santad::logs::endpoint_security::Logger>)logger
|
||||
enricher:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::Enricher>)enricher
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
authResultCache:
|
||||
(std::shared_ptr<santa::santad::event_providers::AuthResultCache>)authResultCache
|
||||
prefixTree:(std::shared_ptr<santa::common::PrefixTree<santa::common::Unit>>)prefixTree
|
||||
processTree:(std::shared_ptr<santa::santad::process_tree::ProcessTree>)processTree;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::Logger>)logger
|
||||
enricher:(std::shared_ptr<santa::Enricher>)enricher
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
authResultCache:(std::shared_ptr<santa::AuthResultCache>)authResultCache
|
||||
prefixTree:(std::shared_ptr<santa::PrefixTree<santa::Unit>>)prefixTree
|
||||
processTree:
|
||||
(std::shared_ptr<santa::santad::process_tree::ProcessTree>)processTree;
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <EndpointSecurity/EndpointSecurity.h>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
#import "Source/common/SNTLogging.h"
|
||||
#include "Source/common/String.h"
|
||||
@@ -26,15 +27,15 @@
|
||||
#include "Source/santad/Metrics.h"
|
||||
#include "Source/santad/ProcessTree/process_tree.h"
|
||||
|
||||
using santa::common::PrefixTree;
|
||||
using santa::common::Unit;
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::Enricher;
|
||||
using santa::EventDisposition;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
using santa::PrefixTree;
|
||||
using santa::Unit;
|
||||
using santa::santad::process_tree::ProcessTree;
|
||||
|
||||
es_file_t *GetTargetFileForPrefixTree(const es_message_t *msg) {
|
||||
@@ -61,7 +62,7 @@ es_file_t *GetTargetFileForPrefixTree(const es_message_t *msg) {
|
||||
}
|
||||
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<Logger>)logger
|
||||
enricher:(std::shared_ptr<Enricher>)enricher
|
||||
compilerController:(SNTCompilerController *)compilerController
|
||||
@@ -70,7 +71,7 @@ es_file_t *GetTargetFileForPrefixTree(const es_message_t *msg) {
|
||||
processTree:(std::shared_ptr<ProcessTree>)processTree {
|
||||
self = [super initWithESAPI:std::move(esApi)
|
||||
metrics:std::move(metrics)
|
||||
processor:santa::santad::Processor::kRecorder
|
||||
processor:santa::Processor::kRecorder
|
||||
processTree:std::move(processTree)];
|
||||
if (self) {
|
||||
_enricher = enricher;
|
||||
@@ -141,7 +142,7 @@ es_file_t *GetTargetFileForPrefixTree(const es_message_t *msg) {
|
||||
}
|
||||
|
||||
// Only log file changes that match the given regex
|
||||
NSString *targetPath = santa::common::StringToNSString(targetFile->path.data);
|
||||
NSString *targetPath = santa::StringToNSString(targetFile->path.data);
|
||||
if (![[self.configurator fileChangesRegex]
|
||||
numberOfMatchesInString:targetPath
|
||||
options:0
|
||||
@@ -186,16 +187,36 @@ es_file_t *GetTargetFileForPrefixTree(const es_message_t *msg) {
|
||||
}
|
||||
|
||||
- (void)enable {
|
||||
[super subscribe:{
|
||||
ES_EVENT_TYPE_NOTIFY_CLOSE,
|
||||
ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA,
|
||||
ES_EVENT_TYPE_NOTIFY_EXEC,
|
||||
ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
ES_EVENT_TYPE_NOTIFY_FORK,
|
||||
ES_EVENT_TYPE_NOTIFY_LINK,
|
||||
ES_EVENT_TYPE_NOTIFY_RENAME,
|
||||
ES_EVENT_TYPE_NOTIFY_UNLINK,
|
||||
}];
|
||||
// clang-format off
|
||||
std::set<es_event_type_t> events{
|
||||
ES_EVENT_TYPE_NOTIFY_CLOSE,
|
||||
ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA,
|
||||
ES_EVENT_TYPE_NOTIFY_EXEC,
|
||||
ES_EVENT_TYPE_NOTIFY_EXIT,
|
||||
ES_EVENT_TYPE_NOTIFY_FORK,
|
||||
ES_EVENT_TYPE_NOTIFY_LINK,
|
||||
ES_EVENT_TYPE_NOTIFY_RENAME,
|
||||
ES_EVENT_TYPE_NOTIFY_UNLINK,
|
||||
};
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
if (@available(macOS 13.0, *)) {
|
||||
events.insert({
|
||||
ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK,
|
||||
ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH,
|
||||
ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH,
|
||||
ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT});
|
||||
}
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
[super subscribe:events];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#include "Source/common/PrefixTree.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
#include "Source/common/TestUtils.h"
|
||||
@@ -38,15 +39,15 @@
|
||||
#include "Source/santad/Metrics.h"
|
||||
#import "Source/santad/SNTCompilerController.h"
|
||||
|
||||
using santa::common::PrefixTree;
|
||||
using santa::common::Unit;
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::Processor;
|
||||
using santa::santad::event_providers::AuthResultCache;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::AuthResultCache;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::Enricher;
|
||||
using santa::EventDisposition;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
using santa::PrefixTree;
|
||||
using santa::Processor;
|
||||
using santa::Unit;
|
||||
|
||||
class MockEnricher : public Enricher {
|
||||
public:
|
||||
@@ -90,6 +91,24 @@ class MockLogger : public Logger {
|
||||
ES_EVENT_TYPE_NOTIFY_FORK, ES_EVENT_TYPE_NOTIFY_EXIT, ES_EVENT_TYPE_NOTIFY_LINK,
|
||||
ES_EVENT_TYPE_NOTIFY_RENAME, ES_EVENT_TYPE_NOTIFY_UNLINK,
|
||||
};
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
if (@available(macOS 13.0, *)) {
|
||||
expectedEventSubs.insert({
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK,
|
||||
ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK,
|
||||
ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH,
|
||||
ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH,
|
||||
ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT,
|
||||
ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN,
|
||||
ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT,
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
|
||||
id recorderClient = [[SNTEndpointSecurityRecorder alloc] initWithESAPI:mockESApi
|
||||
@@ -100,6 +119,10 @@ class MockLogger : public Logger {
|
||||
|
||||
[recorderClient enable];
|
||||
|
||||
for (const auto &event : expectedEventSubs) {
|
||||
XCTAssertNoThrow(santa::EventTypeToString(event));
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
}
|
||||
|
||||
@@ -172,7 +195,7 @@ es_file_t targetFileMissesRegex = MakeESFile("/foo/misses");
|
||||
[mockCC stopMocking];
|
||||
}
|
||||
|
||||
- (void)testHandleMessageWithCloseMappedWriteable {
|
||||
- (void)testHandleEventCloseMappedWritableMatchesRegex {
|
||||
#if HAVE_MACOS_13
|
||||
if (@available(macOS 13.0, *)) {
|
||||
// CLOSE not modified, but was_mapped_writable, should remove from cache,
|
||||
@@ -199,12 +222,12 @@ es_file_t targetFileMissesRegex = MakeESFile("/foo/misses");
|
||||
XCTAssertSemaTrue(*sema, 5, "Log wasn't called within expected time window");
|
||||
};
|
||||
|
||||
[self handleMessageWithMatchCalls:YES withMissCalls:NO withBlock:testBlock];
|
||||
[self handleMessageShouldLog:YES shouldRemoveFromCache:YES withBlock:testBlock];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)testHandleEventCloseNotModifiedWithWasMappedWritable {
|
||||
- (void)testHandleEventCloseMappedWritableMissesRegex {
|
||||
#if HAVE_MACOS_13
|
||||
if (@available(macOS 13.0, *)) {
|
||||
// CLOSE not modified, but was_mapped_writable, remove from cache, and does not match
|
||||
@@ -220,13 +243,15 @@ es_file_t targetFileMissesRegex = MakeESFile("/foo/misses");
|
||||
esMsg->event.close.target = &targetFileMissesRegex;
|
||||
Message msg(mockESApi, esMsg);
|
||||
|
||||
OCMExpect([mockCC handleEvent:msg withLogger:nullptr]).ignoringNonObjectArgs();
|
||||
|
||||
XCTAssertNoThrow([recorderClient handleMessage:Message(mockESApi, esMsg)
|
||||
recordEventMetrics:^(EventDisposition d) {
|
||||
XCTFail("Metrics record callback should not be called here");
|
||||
}]);
|
||||
};
|
||||
|
||||
[self handleMessageWithMatchCalls:NO withMissCalls:YES withBlock:testBlock];
|
||||
[self handleMessageShouldLog:NO shouldRemoveFromCache:YES withBlock:testBlock];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -26,10 +26,8 @@
|
||||
@interface SNTEndpointSecurityTamperResistance
|
||||
: SNTEndpointSecurityClient <SNTEndpointSecurityEventHandler>
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::santad::logs::endpoint_security::Logger>)logger;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<santa::Logger>)logger;
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,18 +15,20 @@
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityTamperResistance.h"
|
||||
|
||||
#include <EndpointSecurity/ESTypes.h>
|
||||
#include <bsm/libbsm.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#import "Source/common/SNTLogging.h"
|
||||
#include "Source/santad/DataLayer/WatchItemPolicy.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EventDisposition;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
using santa::WatchItemPathType;
|
||||
|
||||
static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-driver";
|
||||
|
||||
@@ -35,11 +37,11 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
}
|
||||
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
logger:(std::shared_ptr<Logger>)logger {
|
||||
self = [super initWithESAPI:std::move(esApi)
|
||||
metrics:std::move(metrics)
|
||||
processor:santa::santad::Processor::kTamperResistance];
|
||||
processor:santa::Processor::kTamperResistance];
|
||||
if (self) {
|
||||
_logger = logger;
|
||||
|
||||
@@ -85,6 +87,26 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
break;
|
||||
}
|
||||
|
||||
case ES_EVENT_TYPE_AUTH_SIGNAL: {
|
||||
// Only block signals sent to us and not from launchd.
|
||||
if (audit_token_to_pid(esMsg->event.signal.target->audit_token) == getpid() &&
|
||||
audit_token_to_pid(esMsg->process->audit_token) != 1) {
|
||||
LOGW(@"Preventing attempt to kill Santa daemon");
|
||||
result = ES_AUTH_RESULT_DENY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ES_EVENT_TYPE_AUTH_EXEC: {
|
||||
// When not running a debug build, prevent attempts to kill Santa
|
||||
// by launchctl commands.
|
||||
#ifndef DEBUG
|
||||
result = ValidateLaunchctlExec(esMsg);
|
||||
if (result == ES_AUTH_RESULT_DENY) LOGW(@"Preventing attempt to kill Santa daemon");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case ES_EVENT_TYPE_AUTH_KEXTLOAD: {
|
||||
// TODO(mlw): Since we don't package the kext anymore, we should consider removing this.
|
||||
// TODO(mlw): Consider logging when kext loads are attempted.
|
||||
@@ -120,15 +142,53 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
for (const auto &path : protectedPaths) {
|
||||
watchPaths.push_back({path, WatchItemPathType::kLiteral});
|
||||
}
|
||||
watchPaths.push_back({"/Library/SystemExtensions", WatchItemPathType::kPrefix});
|
||||
watchPaths.push_back({"/bin/launchctl", WatchItemPathType::kLiteral});
|
||||
|
||||
// Begin watching the protected set
|
||||
[super muteTargetPaths:watchPaths];
|
||||
|
||||
[super subscribeAndClearCache:{
|
||||
ES_EVENT_TYPE_AUTH_KEXTLOAD,
|
||||
ES_EVENT_TYPE_AUTH_SIGNAL,
|
||||
ES_EVENT_TYPE_AUTH_EXEC,
|
||||
ES_EVENT_TYPE_AUTH_UNLINK,
|
||||
ES_EVENT_TYPE_AUTH_RENAME,
|
||||
}];
|
||||
}
|
||||
|
||||
es_auth_result_t ValidateLaunchctlExec(const Message &esMsg) {
|
||||
es_string_token_t exec_path = esMsg->event.exec.target->executable->path;
|
||||
if (strncmp(exec_path.data, "/bin/launchctl", exec_path.length) != 0) {
|
||||
return ES_AUTH_RESULT_ALLOW;
|
||||
}
|
||||
|
||||
// Ensure there are at least 2 arguments after the command
|
||||
std::shared_ptr<EndpointSecurityAPI> esApi = esMsg.ESAPI();
|
||||
uint32_t argCount = esApi->ExecArgCount(&esMsg->event.exec);
|
||||
if (argCount < 2) {
|
||||
return ES_AUTH_RESULT_ALLOW;
|
||||
}
|
||||
|
||||
// Check for some allowed subcommands
|
||||
es_string_token_t arg = esApi->ExecArg(&esMsg->event.exec, 1);
|
||||
static const std::unordered_set<std::string> safe_commands{
|
||||
"blame", "help", "hostinfo", "list", "plist", "print", "procinfo",
|
||||
};
|
||||
if (safe_commands.find(std::string(arg.data, arg.length)) != safe_commands.end()) {
|
||||
return ES_AUTH_RESULT_ALLOW;
|
||||
}
|
||||
|
||||
// Check whether com.google.santa.daemon is in the argument list.
|
||||
// launchctl no longer accepts PIDs to operate on.
|
||||
for (int i = 2; i < argCount; i++) {
|
||||
es_string_token_t arg = esApi->ExecArg(&esMsg->event.exec, i);
|
||||
if (strnstr(arg.data, "com.google.santa.daemon", arg.length) != NULL) {
|
||||
return ES_AUTH_RESULT_DENY;
|
||||
}
|
||||
}
|
||||
|
||||
return ES_AUTH_RESULT_ALLOW;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityTamperResistance.h"
|
||||
#import "Source/santad/Metrics.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::data_layer::WatchItemPathType;
|
||||
using santa::santad::event_providers::endpoint_security::Client;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::Client;
|
||||
using santa::EventDisposition;
|
||||
using santa::Message;
|
||||
using santa::WatchItemPathType;
|
||||
|
||||
static constexpr std::string_view kEventsDBPath = "/private/var/db/santa/events.db";
|
||||
static constexpr std::string_view kRulesDBPath = "/private/var/db/santa/rules.db";
|
||||
@@ -49,9 +49,8 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
- (void)testEnable {
|
||||
// Ensure the client subscribes to expected event types
|
||||
std::set<es_event_type_t> expectedEventSubs{
|
||||
ES_EVENT_TYPE_AUTH_KEXTLOAD,
|
||||
ES_EVENT_TYPE_AUTH_UNLINK,
|
||||
ES_EVENT_TYPE_AUTH_RENAME,
|
||||
ES_EVENT_TYPE_AUTH_KEXTLOAD, ES_EVENT_TYPE_AUTH_SIGNAL, ES_EVENT_TYPE_AUTH_EXEC,
|
||||
ES_EVENT_TYPE_AUTH_UNLINK, ES_EVENT_TYPE_AUTH_RENAME,
|
||||
};
|
||||
|
||||
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
@@ -70,6 +69,8 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
// Setup mocks to handle muting the rules db and events db
|
||||
EXPECT_CALL(*mockESApi, MuteTargetPath(testing::_, testing::_, WatchItemPathType::kLiteral))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
EXPECT_CALL(*mockESApi, MuteTargetPath(testing::_, testing::_, WatchItemPathType::kPrefix))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
SNTEndpointSecurityTamperResistance *tamperClient =
|
||||
[[SNTEndpointSecurityTamperResistance alloc] initWithESAPI:mockESApi
|
||||
@@ -79,6 +80,10 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
|
||||
[mockTamperClient enable];
|
||||
|
||||
for (const auto &event : expectedEventSubs) {
|
||||
XCTAssertNoThrow(santa::EventTypeToString(event));
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
[mockTamperClient stopMocking];
|
||||
}
|
||||
@@ -86,7 +91,7 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
- (void)testHandleMessage {
|
||||
es_file_t file = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&file);
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_AUTH_EXEC, &proc, ActionType::Auth);
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_AUTH_LINK, &proc, ActionType::Auth);
|
||||
|
||||
es_file_t fileEventsDB = MakeESFile(kEventsDBPath.data());
|
||||
es_file_t fileRulesDB = MakeESFile(kRulesDBPath.data());
|
||||
@@ -106,6 +111,12 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
{&benignTok, ES_AUTH_RESULT_ALLOW},
|
||||
};
|
||||
|
||||
std::map<std::pair<pid_t, pid_t>, es_auth_result_t> pidsToResult{
|
||||
{{getpid(), 31838}, ES_AUTH_RESULT_DENY},
|
||||
{{getpid(), 1}, ES_AUTH_RESULT_ALLOW},
|
||||
{{435, 98381}, ES_AUTH_RESULT_ALLOW},
|
||||
};
|
||||
|
||||
dispatch_semaphore_t semaMetrics = dispatch_semaphore_create(0);
|
||||
|
||||
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
@@ -232,6 +243,31 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
|
||||
}
|
||||
}
|
||||
|
||||
// Check SIGNAL tamper events
|
||||
{
|
||||
esMsg.event_type = ES_EVENT_TYPE_AUTH_SIGNAL;
|
||||
|
||||
for (const auto &kv : pidsToResult) {
|
||||
Message msg(mockESApi, &esMsg);
|
||||
es_process_t target_proc = MakeESProcess(&file);
|
||||
target_proc.audit_token = MakeAuditToken(kv.first.first, 42);
|
||||
esMsg.event.signal.target = &target_proc;
|
||||
esMsg.process->audit_token = MakeAuditToken(kv.first.second, 42);
|
||||
|
||||
[mockTamperClient
|
||||
handleMessage:std::move(msg)
|
||||
recordEventMetrics:^(EventDisposition d) {
|
||||
XCTAssertEqual(d, kv.second == ES_AUTH_RESULT_DENY ? EventDisposition::kProcessed
|
||||
: EventDisposition::kDropped);
|
||||
dispatch_semaphore_signal(semaMetrics);
|
||||
}];
|
||||
|
||||
XCTAssertSemaTrue(semaMetrics, 5, "Metrics not recorded within expected window");
|
||||
XCTAssertEqual(gotAuthResult, kv.second);
|
||||
XCTAssertEqual(gotCachable, kv.second == ES_AUTH_RESULT_ALLOW);
|
||||
}
|
||||
}
|
||||
|
||||
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
|
||||
XCTAssertTrue(OCMVerifyAll(mockTamperClient));
|
||||
|
||||
|
||||
@@ -21,10 +21,9 @@
|
||||
@interface SNTEndpointSecurityTreeAwareClient : SNTEndpointSecurityClient
|
||||
@property std::shared_ptr<santa::santad::process_tree::ProcessTree> processTree;
|
||||
|
||||
- (instancetype)
|
||||
initWithESAPI:
|
||||
(std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::santad::Metrics>)metrics
|
||||
processor:(santa::santad::Processor)processor
|
||||
processTree:(std::shared_ptr<santa::santad::process_tree::ProcessTree>)processTree;
|
||||
- (instancetype)initWithESAPI:(std::shared_ptr<santa::EndpointSecurityAPI>)esApi
|
||||
metrics:(std::shared_ptr<santa::Metrics>)metrics
|
||||
processor:(santa::Processor)processor
|
||||
processTree:
|
||||
(std::shared_ptr<santa::santad::process_tree::ProcessTree>)processTree;
|
||||
@end
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
#include "Source/santad/ProcessTree/process_tree.h"
|
||||
#include "Source/santad/ProcessTree/process_tree_macos.h"
|
||||
|
||||
using santa::santad::EventDisposition;
|
||||
using santa::santad::Metrics;
|
||||
using santa::santad::Processor;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EventDisposition;
|
||||
using santa::Message;
|
||||
using santa::Metrics;
|
||||
using santa::Processor;
|
||||
|
||||
@implementation SNTEndpointSecurityTreeAwareClient {
|
||||
std::vector<bool> _addedEvents;
|
||||
|
||||
@@ -30,51 +30,48 @@
|
||||
|
||||
// Forward declarations
|
||||
@class SNTStoredEvent;
|
||||
namespace santa::santad::logs::endpoint_security {
|
||||
namespace santa {
|
||||
class LoggerPeer;
|
||||
}
|
||||
|
||||
namespace santa::santad::logs::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
static std::unique_ptr<Logger> Create(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTEventLogType log_type, SNTDecisionCache *decision_cache, NSString *event_log_path,
|
||||
NSString *spool_log_path, size_t spool_dir_size_threshold, size_t spool_file_size_threshold,
|
||||
uint64_t spool_flush_timeout_ms);
|
||||
static std::unique_ptr<Logger> Create(std::shared_ptr<santa::EndpointSecurityAPI> esapi,
|
||||
SNTEventLogType log_type, SNTDecisionCache *decision_cache,
|
||||
NSString *event_log_path, NSString *spool_log_path,
|
||||
size_t spool_dir_size_threshold,
|
||||
size_t spool_file_size_threshold,
|
||||
uint64_t spool_flush_timeout_ms);
|
||||
|
||||
Logger(std::shared_ptr<serializers::Serializer> serializer,
|
||||
std::shared_ptr<writers::Writer> writer);
|
||||
Logger(std::shared_ptr<santa::Serializer> serializer, std::shared_ptr<santa::Writer> writer);
|
||||
|
||||
virtual ~Logger() = default;
|
||||
|
||||
virtual void Log(
|
||||
std::unique_ptr<santa::santad::event_providers::endpoint_security::EnrichedMessage> msg);
|
||||
virtual void Log(std::unique_ptr<santa::EnrichedMessage> msg);
|
||||
|
||||
void LogAllowlist(const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const std::string_view hash);
|
||||
void LogAllowlist(const santa::Message &msg, const std::string_view hash);
|
||||
|
||||
void LogBundleHashingEvents(NSArray<SNTStoredEvent *> *events);
|
||||
|
||||
void LogDiskAppeared(NSDictionary *props);
|
||||
void LogDiskDisappeared(NSDictionary *props);
|
||||
|
||||
virtual void LogFileAccess(
|
||||
const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision);
|
||||
virtual void LogFileAccess(const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision);
|
||||
|
||||
void Flush();
|
||||
|
||||
friend class santa::santad::logs::endpoint_security::LoggerPeer;
|
||||
friend class santa::LoggerPeer;
|
||||
|
||||
private:
|
||||
std::shared_ptr<serializers::Serializer> serializer_;
|
||||
std::shared_ptr<writers::Writer> writer_;
|
||||
std::shared_ptr<santa::Serializer> serializer_;
|
||||
std::shared_ptr<santa::Writer> writer_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,19 +27,19 @@
|
||||
#include "Source/santad/Logs/EndpointSecurity/Writers/Syslog.h"
|
||||
#include "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::serializers::BasicString;
|
||||
using santa::santad::logs::endpoint_security::serializers::Empty;
|
||||
using santa::santad::logs::endpoint_security::serializers::Protobuf;
|
||||
using santa::santad::logs::endpoint_security::writers::File;
|
||||
using santa::santad::logs::endpoint_security::writers::Null;
|
||||
using santa::santad::logs::endpoint_security::writers::Spool;
|
||||
using santa::santad::logs::endpoint_security::writers::Syslog;
|
||||
using santa::BasicString;
|
||||
using santa::Empty;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::File;
|
||||
using santa::Message;
|
||||
using santa::Null;
|
||||
using santa::Protobuf;
|
||||
using santa::Spool;
|
||||
using santa::Syslog;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
// Flush the write buffer every 5 seconds
|
||||
static const uint64_t kFlushBufferTimeoutMS = 10000;
|
||||
@@ -81,8 +81,7 @@ std::unique_ptr<Logger> Logger::Create(std::shared_ptr<EndpointSecurityAPI> esap
|
||||
}
|
||||
}
|
||||
|
||||
Logger::Logger(std::shared_ptr<serializers::Serializer> serializer,
|
||||
std::shared_ptr<writers::Writer> writer)
|
||||
Logger::Logger(std::shared_ptr<santa::Serializer> serializer, std::shared_ptr<santa::Writer> writer)
|
||||
: serializer_(std::move(serializer)), writer_(std::move(writer)) {}
|
||||
|
||||
void Logger::Log(std::unique_ptr<EnrichedMessage> msg) {
|
||||
@@ -107,11 +106,10 @@ void Logger::LogDiskDisappeared(NSDictionary *props) {
|
||||
writer_->Write(serializer_->SerializeDiskDisappeared(props));
|
||||
}
|
||||
|
||||
void Logger::LogFileAccess(
|
||||
const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision) {
|
||||
void Logger::LogFileAccess(const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision) {
|
||||
writer_->Write(serializer_->SerializeFileAccess(policy_version, policy_name, msg,
|
||||
enriched_process, target, decision));
|
||||
}
|
||||
@@ -120,4 +118,4 @@ void Logger::Flush() {
|
||||
writer_->Flush();
|
||||
}
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
@@ -39,21 +39,21 @@
|
||||
#include "Source/santad/Logs/EndpointSecurity/Writers/Syslog.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Writers/Writer.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedClose;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFile;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::Logger;
|
||||
using santa::santad::logs::endpoint_security::serializers::BasicString;
|
||||
using santa::santad::logs::endpoint_security::serializers::Empty;
|
||||
using santa::santad::logs::endpoint_security::serializers::Protobuf;
|
||||
using santa::santad::logs::endpoint_security::writers::File;
|
||||
using santa::santad::logs::endpoint_security::writers::Null;
|
||||
using santa::santad::logs::endpoint_security::writers::Spool;
|
||||
using santa::santad::logs::endpoint_security::writers::Syslog;
|
||||
using santa::BasicString;
|
||||
using santa::Empty;
|
||||
using santa::EnrichedClose;
|
||||
using santa::EnrichedFile;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::File;
|
||||
using santa::Logger;
|
||||
using santa::Message;
|
||||
using santa::Null;
|
||||
using santa::Protobuf;
|
||||
using santa::Spool;
|
||||
using santa::Syslog;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security {
|
||||
namespace santa {
|
||||
|
||||
class LoggerPeer : public Logger {
|
||||
public:
|
||||
@@ -62,14 +62,14 @@ class LoggerPeer : public Logger {
|
||||
|
||||
LoggerPeer(std::unique_ptr<Logger> l) : Logger(l->serializer_, l->writer_) {}
|
||||
|
||||
std::shared_ptr<serializers::Serializer> Serializer() { return serializer_; }
|
||||
std::shared_ptr<santa::Serializer> Serializer() { return serializer_; }
|
||||
|
||||
std::shared_ptr<writers::Writer> Writer() { return writer_; }
|
||||
std::shared_ptr<santa::Writer> Writer() { return writer_; }
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::logs::endpoint_security::LoggerPeer;
|
||||
using santa::LoggerPeer;
|
||||
|
||||
class MockSerializer : public Empty {
|
||||
public:
|
||||
@@ -81,12 +81,10 @@ class MockSerializer : public Empty {
|
||||
MOCK_METHOD(std::vector<uint8_t>, SerializeDiskAppeared, (NSDictionary *));
|
||||
MOCK_METHOD(std::vector<uint8_t>, SerializeDiskDisappeared, (NSDictionary *));
|
||||
|
||||
MOCK_METHOD(
|
||||
std::vector<uint8_t>, SerializeFileAccess,
|
||||
(const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision));
|
||||
MOCK_METHOD(std::vector<uint8_t>, SerializeFileAccess,
|
||||
(const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::Message &msg, const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision));
|
||||
};
|
||||
|
||||
class MockWriter : public Null {
|
||||
|
||||
@@ -21,19 +21,17 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Logger.h"
|
||||
|
||||
class MockLogger : public santa::santad::logs::endpoint_security::Logger {
|
||||
class MockLogger : public santa::Logger {
|
||||
public:
|
||||
using Logger::Logger;
|
||||
|
||||
MockLogger() : Logger(nullptr, nullptr) {}
|
||||
|
||||
MOCK_METHOD(
|
||||
void, LogFileAccess,
|
||||
(const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess
|
||||
&enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision));
|
||||
MOCK_METHOD(void, LogFileAccess,
|
||||
(const std::string &policy_version,
|
||||
const std::string &policy_name, const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision));
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,52 +21,53 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#import "Source/common/SNTCachedDecision.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Serializer.h"
|
||||
#import "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
class BasicString : public Serializer {
|
||||
public:
|
||||
static std::shared_ptr<BasicString> Create(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache, bool prefix_time_name = true);
|
||||
static std::shared_ptr<BasicString> Create(std::shared_ptr<santa::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache,
|
||||
bool prefix_time_name = true);
|
||||
|
||||
BasicString(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache, bool prefix_time_name);
|
||||
BasicString(std::shared_ptr<santa::EndpointSecurityAPI> esapi, SNTDecisionCache *decision_cache,
|
||||
bool prefix_time_name);
|
||||
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExec &,
|
||||
SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExec &, SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedCSInvalidated &) override;
|
||||
#if HAVE_MACOS_13
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionUnlock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingAttach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingDetach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogout &) override;
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> SerializeFileAccess(
|
||||
const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision) override;
|
||||
std::vector<uint8_t> SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name,
|
||||
const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target,
|
||||
FileAccessPolicyDecision decision) override;
|
||||
|
||||
std::vector<uint8_t> SerializeAllowlist(
|
||||
const santa::santad::event_providers::endpoint_security::Message &,
|
||||
const std::string_view) override;
|
||||
std::vector<uint8_t> SerializeAllowlist(const santa::Message &, const std::string_view) override;
|
||||
|
||||
std::vector<uint8_t> SerializeBundleHashingEvent(SNTStoredEvent *) override;
|
||||
|
||||
@@ -77,10 +78,10 @@ class BasicString : public Serializer {
|
||||
std::string CreateDefaultString(size_t reserved_size = 512);
|
||||
std::vector<uint8_t> FinalizeString(std::string &str);
|
||||
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi_;
|
||||
std::shared_ptr<santa::EndpointSecurityAPI> esapi_;
|
||||
bool prefix_time_name_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,26 +35,37 @@
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Utilities.h"
|
||||
#import "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedClose;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExchange;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExec;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExit;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFork;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedLink;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedRename;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedUnlink;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::MountFromName;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::NonNull;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::Pid;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::Pidversion;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::RealGroup;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::RealUser;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EnrichedClose;
|
||||
using santa::EnrichedCSInvalidated;
|
||||
using santa::EnrichedEventType;
|
||||
using santa::EnrichedExchange;
|
||||
using santa::EnrichedExec;
|
||||
using santa::EnrichedExit;
|
||||
using santa::EnrichedFork;
|
||||
using santa::EnrichedLink;
|
||||
using santa::EnrichedLoginLogin;
|
||||
using santa::EnrichedLoginLogout;
|
||||
using santa::EnrichedLoginWindowSessionLock;
|
||||
using santa::EnrichedLoginWindowSessionLogin;
|
||||
using santa::EnrichedLoginWindowSessionLogout;
|
||||
using santa::EnrichedLoginWindowSessionUnlock;
|
||||
using santa::EnrichedOpenSSHLogin;
|
||||
using santa::EnrichedOpenSSHLogout;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::EnrichedRename;
|
||||
using santa::EnrichedScreenSharingAttach;
|
||||
using santa::EnrichedScreenSharingDetach;
|
||||
using santa::EnrichedUnlink;
|
||||
using santa::Message;
|
||||
using santa::MountFromName;
|
||||
using santa::NonNull;
|
||||
using santa::Pid;
|
||||
using santa::Pidversion;
|
||||
using santa::RealGroup;
|
||||
using santa::RealUser;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
static inline SanitizableString FilePath(const es_file_t *file) {
|
||||
return SanitizableString(file);
|
||||
@@ -168,6 +179,68 @@ static inline void AppendUserGroup(std::string &str, const audit_token_t &tok,
|
||||
str.append(group.has_value() ? group->get()->c_str() : "(null)");
|
||||
}
|
||||
|
||||
static inline void AppendInstigator(std::string &str, const EnrichedEventType &event) {
|
||||
AppendProcess(str, event->process);
|
||||
AppendUserGroup(str, event->process->audit_token, event.instigator().real_user(),
|
||||
event.instigator().real_group());
|
||||
}
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
|
||||
static inline void AppendEventUser(std::string &str, const es_string_token_t &user,
|
||||
std::optional<uid_t> uid) {
|
||||
if (user.length > 0) {
|
||||
str.append("|event_user=");
|
||||
str.append(user.data);
|
||||
}
|
||||
|
||||
if (uid.has_value()) {
|
||||
str.append("|event_uid=");
|
||||
str.append(std::to_string(uid.value()));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void AppendGraphicalSession(std::string &str, es_graphical_session_id_t session_id) {
|
||||
str.append("|graphical_session_id=");
|
||||
str.append(std::to_string(session_id));
|
||||
}
|
||||
|
||||
static inline void AppendSocketAddress(std::string &str, es_address_type_t type,
|
||||
es_string_token_t addr) {
|
||||
str.append("|address_type=");
|
||||
switch (type) {
|
||||
case ES_ADDRESS_TYPE_NONE: str.append("none"); break;
|
||||
case ES_ADDRESS_TYPE_IPV4: str.append("ipv4"); break;
|
||||
case ES_ADDRESS_TYPE_IPV6: str.append("ipv6"); break;
|
||||
case ES_ADDRESS_TYPE_NAMED_SOCKET: str.append("named_socket"); break;
|
||||
default: str.append("unknown"); break;
|
||||
}
|
||||
|
||||
if (addr.length > 0) {
|
||||
str.append("|address=");
|
||||
str.append(SanitizableString(addr).Sanitized());
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string GetOpenSSHLoginResult(std::string &str,
|
||||
es_openssh_login_result_type_t result) {
|
||||
switch (result) {
|
||||
case ES_OPENSSH_LOGIN_EXCEED_MAXTRIES: return "LOGIN_EXCEED_MAXTRIES";
|
||||
case ES_OPENSSH_LOGIN_ROOT_DENIED: return "LOGIN_ROOT_DENIED";
|
||||
case ES_OPENSSH_AUTH_SUCCESS: return "AUTH_SUCCESS";
|
||||
case ES_OPENSSH_AUTH_FAIL_NONE: return "AUTH_FAIL_NONE";
|
||||
case ES_OPENSSH_AUTH_FAIL_PASSWD: return "AUTH_FAIL_PASSWD";
|
||||
case ES_OPENSSH_AUTH_FAIL_KBDINT: return "AUTH_FAIL_KBDINT";
|
||||
case ES_OPENSSH_AUTH_FAIL_PUBKEY: return "AUTH_FAIL_PUBKEY";
|
||||
case ES_OPENSSH_AUTH_FAIL_HOSTBASED: return "AUTH_FAIL_HOSTBASED";
|
||||
case ES_OPENSSH_AUTH_FAIL_GSSAPI: return "AUTH_FAIL_GSSAPI";
|
||||
case ES_OPENSSH_INVALID_USER: return "INVALID_USER";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
static char *FormattedDateString(char *buf, size_t len) {
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
@@ -219,37 +292,30 @@ std::vector<uint8_t> BasicString::FinalizeString(std::string &str) {
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedClose &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=WRITE|path=");
|
||||
str.append(FilePath(esm.event.close.target).Sanitized());
|
||||
str.append(FilePath(msg->event.close.target).Sanitized());
|
||||
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExchange &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=EXCHANGE|path=");
|
||||
str.append(FilePath(esm.event.exchangedata.file1).Sanitized());
|
||||
str.append(FilePath(msg->event.exchangedata.file1).Sanitized());
|
||||
str.append("|newpath=");
|
||||
str.append(FilePath(esm.event.exchangedata.file2).Sanitized());
|
||||
str.append(FilePath(msg->event.exchangedata.file2).Sanitized());
|
||||
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExec &msg, SNTCachedDecision *cd) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString(1024); // EXECs tend to be bigger, reserve more space.
|
||||
|
||||
str.append("action=EXEC|decision=");
|
||||
@@ -285,27 +351,27 @@ std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExec &msg, SNTC
|
||||
}
|
||||
|
||||
str.append("|pid=");
|
||||
str.append(std::to_string(Pid(esm.event.exec.target->audit_token)));
|
||||
str.append(std::to_string(Pid(msg->event.exec.target->audit_token)));
|
||||
str.append("|pidversion=");
|
||||
str.append(std::to_string(Pidversion(esm.event.exec.target->audit_token)));
|
||||
str.append(std::to_string(Pidversion(msg->event.exec.target->audit_token)));
|
||||
str.append("|ppid=");
|
||||
str.append(std::to_string(esm.event.exec.target->original_ppid));
|
||||
str.append(std::to_string(msg->event.exec.target->original_ppid));
|
||||
|
||||
AppendUserGroup(str, esm.event.exec.target->audit_token, msg.instigator().real_user(),
|
||||
AppendUserGroup(str, msg->event.exec.target->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
|
||||
str.append("|mode=");
|
||||
str.append(GetModeString(cd.decisionClientMode));
|
||||
str.append("|path=");
|
||||
str.append(FilePath(esm.event.exec.target->executable).Sanitized());
|
||||
str.append(FilePath(msg->event.exec.target->executable).Sanitized());
|
||||
|
||||
NSString *origPath = Utilities::OriginalPathForTranslocation(esm.event.exec.target);
|
||||
NSString *origPath = santa::OriginalPathForTranslocation(msg->event.exec.target);
|
||||
if (origPath) {
|
||||
str.append("|origpath=");
|
||||
str.append(SanitizableString(origPath).Sanitized());
|
||||
}
|
||||
|
||||
uint32_t argCount = esapi_->ExecArgCount(&esm.event.exec);
|
||||
uint32_t argCount = esapi_->ExecArgCount(&msg->event.exec);
|
||||
if (argCount > 0) {
|
||||
str.append("|args=");
|
||||
for (uint32_t i = 0; i < argCount; i++) {
|
||||
@@ -313,7 +379,7 @@ std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExec &msg, SNTC
|
||||
str.append(" ");
|
||||
}
|
||||
|
||||
str.append(SanitizableString(esapi_->ExecArg(&esm.event.exec, i)).Sanitized());
|
||||
str.append(SanitizableString(esapi_->ExecArg(&msg->event.exec, i)).Sanitized());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,113 +387,269 @@ std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExec &msg, SNTC
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedExit &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=EXIT|pid=");
|
||||
str.append(std::to_string(Pid(esm.process->audit_token)));
|
||||
str.append(std::to_string(Pid(msg->process->audit_token)));
|
||||
str.append("|pidversion=");
|
||||
str.append(std::to_string(Pidversion(esm.process->audit_token)));
|
||||
str.append(std::to_string(Pidversion(msg->process->audit_token)));
|
||||
str.append("|ppid=");
|
||||
str.append(std::to_string(esm.process->original_ppid));
|
||||
str.append(std::to_string(msg->process->original_ppid));
|
||||
str.append("|uid=");
|
||||
str.append(std::to_string(RealUser(esm.process->audit_token)));
|
||||
str.append(std::to_string(RealUser(msg->process->audit_token)));
|
||||
str.append("|gid=");
|
||||
str.append(std::to_string(RealGroup(esm.process->audit_token)));
|
||||
str.append(std::to_string(RealGroup(msg->process->audit_token)));
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedFork &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=FORK|pid=");
|
||||
str.append(std::to_string(Pid(esm.event.fork.child->audit_token)));
|
||||
str.append(std::to_string(Pid(msg->event.fork.child->audit_token)));
|
||||
str.append("|pidversion=");
|
||||
str.append(std::to_string(Pidversion(esm.event.fork.child->audit_token)));
|
||||
str.append(std::to_string(Pidversion(msg->event.fork.child->audit_token)));
|
||||
str.append("|ppid=");
|
||||
str.append(std::to_string(esm.event.fork.child->original_ppid));
|
||||
str.append(std::to_string(msg->event.fork.child->original_ppid));
|
||||
str.append("|uid=");
|
||||
str.append(std::to_string(RealUser(esm.event.fork.child->audit_token)));
|
||||
str.append(std::to_string(RealUser(msg->event.fork.child->audit_token)));
|
||||
str.append("|gid=");
|
||||
str.append(std::to_string(RealGroup(esm.event.fork.child->audit_token)));
|
||||
str.append(std::to_string(RealGroup(msg->event.fork.child->audit_token)));
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLink &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LINK|path=");
|
||||
str.append(FilePath(esm.event.link.source).Sanitized());
|
||||
str.append(FilePath(msg->event.link.source).Sanitized());
|
||||
str.append("|newpath=");
|
||||
str.append(FilePath(esm.event.link.target_dir).Sanitized());
|
||||
str.append(FilePath(msg->event.link.target_dir).Sanitized());
|
||||
str.append("/");
|
||||
str.append(SanitizableString(esm.event.link.target_filename).Sanitized());
|
||||
str.append(SanitizableString(msg->event.link.target_filename).Sanitized());
|
||||
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedRename &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=RENAME|path=");
|
||||
str.append(FilePath(esm.event.rename.source).Sanitized());
|
||||
str.append(FilePath(msg->event.rename.source).Sanitized());
|
||||
str.append("|newpath=");
|
||||
|
||||
switch (esm.event.rename.destination_type) {
|
||||
switch (msg->event.rename.destination_type) {
|
||||
case ES_DESTINATION_TYPE_EXISTING_FILE:
|
||||
str.append(FilePath(esm.event.rename.destination.existing_file).Sanitized());
|
||||
str.append(FilePath(msg->event.rename.destination.existing_file).Sanitized());
|
||||
break;
|
||||
case ES_DESTINATION_TYPE_NEW_PATH:
|
||||
str.append(FilePath(esm.event.rename.destination.new_path.dir).Sanitized());
|
||||
str.append(FilePath(msg->event.rename.destination.new_path.dir).Sanitized());
|
||||
str.append("/");
|
||||
str.append(SanitizableString(esm.event.rename.destination.new_path.filename).Sanitized());
|
||||
str.append(SanitizableString(msg->event.rename.destination.new_path.filename).Sanitized());
|
||||
break;
|
||||
default: str.append("(null)"); break;
|
||||
}
|
||||
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedUnlink &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=DELETE|path=");
|
||||
str.append(FilePath(esm.event.unlink.target).Sanitized());
|
||||
str.append(FilePath(msg->event.unlink.target).Sanitized());
|
||||
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedCSInvalidated &msg) {
|
||||
const es_message_t &esm = msg.es_msg();
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=CODESIGNING_INVALIDATED");
|
||||
AppendProcess(str, esm.process);
|
||||
AppendUserGroup(str, esm.process->audit_token, msg.instigator().real_user(),
|
||||
msg.instigator().real_group());
|
||||
AppendInstigator(str, msg);
|
||||
str.append("|codesigning_flags=");
|
||||
str.append([NSString stringWithFormat:@"0x%08x", esm.process->codesigning_flags].UTF8String);
|
||||
str.append([NSString stringWithFormat:@"0x%08x", msg->process->codesigning_flags].UTF8String);
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginWindowSessionLogin &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGIN_WINDOW_SESSION_LOGIN");
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.lw_session_login->username, msg.UID());
|
||||
AppendGraphicalSession(str, msg->event.lw_session_login->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
};
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginWindowSessionLogout &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGIN_WINDOW_SESSION_LOGOUT");
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.lw_session_logout->username, msg.UID());
|
||||
AppendGraphicalSession(str, msg->event.lw_session_logout->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
};
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginWindowSessionLock &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGIN_WINDOW_SESSION_LOCK");
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.lw_session_lock->username, msg.UID());
|
||||
AppendGraphicalSession(str, msg->event.lw_session_lock->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginWindowSessionUnlock &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGIN_WINDOW_SESSION_UNLOCK");
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.lw_session_unlock->username, msg.UID());
|
||||
AppendGraphicalSession(str, msg->event.lw_session_unlock->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedScreenSharingAttach &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=SCREEN_SHARING_ATTACH|success=");
|
||||
str.append(msg->event.screensharing_attach->success ? "true" : "false");
|
||||
|
||||
AppendSocketAddress(str, msg->event.screensharing_attach->source_address_type,
|
||||
msg->event.screensharing_attach->source_address);
|
||||
|
||||
if (msg->event.screensharing_attach->viewer_appleid.length > 0) {
|
||||
str.append("|viewer=");
|
||||
str.append(SanitizableString(msg->event.screensharing_attach->viewer_appleid).Sanitized());
|
||||
}
|
||||
|
||||
if (msg->event.screensharing_attach->authentication_type.length > 0) {
|
||||
str.append("|auth_type=");
|
||||
str.append(SanitizableString(msg->event.screensharing_attach->authentication_type).Sanitized());
|
||||
}
|
||||
|
||||
if (msg->event.screensharing_attach->authentication_username.length > 0) {
|
||||
str.append("|auth_user=");
|
||||
str.append(
|
||||
SanitizableString(msg->event.screensharing_attach->authentication_username).Sanitized());
|
||||
}
|
||||
|
||||
if (msg->event.screensharing_attach->session_username.length > 0) {
|
||||
str.append("|session_user=");
|
||||
str.append(SanitizableString(msg->event.screensharing_attach->session_username).Sanitized());
|
||||
}
|
||||
|
||||
str.append("|existing_session=");
|
||||
str.append(msg->event.screensharing_attach->existing_session ? "true" : "false");
|
||||
|
||||
AppendInstigator(str, msg);
|
||||
AppendGraphicalSession(str, msg->event.screensharing_attach->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedScreenSharingDetach &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=SCREEN_SHARING_DETACH");
|
||||
|
||||
AppendSocketAddress(str, msg->event.screensharing_detach->source_address_type,
|
||||
msg->event.screensharing_detach->source_address);
|
||||
|
||||
if (msg->event.screensharing_detach->viewer_appleid.length > 0) {
|
||||
str.append("|viewer=");
|
||||
str.append(SanitizableString(msg->event.screensharing_detach->viewer_appleid).Sanitized());
|
||||
}
|
||||
|
||||
AppendInstigator(str, msg);
|
||||
AppendGraphicalSession(str, msg->event.screensharing_detach->graphical_session_id);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedOpenSSHLogin &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=OPENSSH_LOGIN|success=");
|
||||
str.append(msg->event.openssh_login->success ? "true" : "false");
|
||||
str.append("|result_type=");
|
||||
str.append(GetOpenSSHLoginResult(str, msg->event.openssh_login->result_type));
|
||||
|
||||
AppendSocketAddress(str, msg->event.openssh_login->source_address_type,
|
||||
msg->event.openssh_login->source_address);
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.openssh_login->username,
|
||||
msg->event.openssh_login->has_uid
|
||||
? std::make_optional<uid_t>(msg->event.openssh_login->uid.uid)
|
||||
: std::nullopt);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedOpenSSHLogout &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=OPENSSH_LOGOUT");
|
||||
|
||||
AppendSocketAddress(str, msg->event.openssh_logout->source_address_type,
|
||||
msg->event.openssh_logout->source_address);
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.openssh_logout->username,
|
||||
std::make_optional<uid_t>(msg->event.openssh_logout->uid));
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginLogin &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGIN|success=");
|
||||
str.append(msg->event.login_login->success ? "true" : "false");
|
||||
if (!msg->event.login_login->success) {
|
||||
str.append("|failure=");
|
||||
str.append(SanitizableString(msg->event.login_login->failure_message).Sanitized());
|
||||
}
|
||||
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.login_login->username,
|
||||
msg->event.login_login->has_uid
|
||||
? std::make_optional<uid_t>(msg->event.login_login->uid.uid)
|
||||
: std::nullopt);
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeMessage(const EnrichedLoginLogout &msg) {
|
||||
std::string str = CreateDefaultString();
|
||||
|
||||
str.append("action=LOGOUT");
|
||||
|
||||
AppendInstigator(str, msg);
|
||||
AppendEventUser(str, msg->event.login_logout->username,
|
||||
std::make_optional<uid_t>(msg->event.login_logout->uid));
|
||||
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
std::vector<uint8_t> BasicString::SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name,
|
||||
const Message &msg,
|
||||
@@ -463,7 +685,7 @@ std::vector<uint8_t> BasicString::SerializeAllowlist(const Message &msg,
|
||||
str.append("|pidversion=");
|
||||
str.append(std::to_string(Pidversion(msg->process->audit_token)));
|
||||
str.append("|path=");
|
||||
str.append(FilePath(Utilities::GetAllowListTargetFile(msg)).Sanitized());
|
||||
str.append(FilePath(santa::GetAllowListTargetFile(msg)).Sanitized());
|
||||
str.append("|sha256=");
|
||||
str.append(hash);
|
||||
|
||||
@@ -493,9 +715,9 @@ std::vector<uint8_t> BasicString::SerializeDiskAppeared(NSDictionary *props) {
|
||||
NSString *dmg_path = nil;
|
||||
NSString *serial = nil;
|
||||
if ([props[@"DADeviceModel"] isEqual:@"Disk Image"]) {
|
||||
dmg_path = Utilities::DiskImageForDevice(props[@"DADevicePath"]);
|
||||
dmg_path = santa::DiskImageForDevice(props[@"DADevicePath"]);
|
||||
} else {
|
||||
serial = Utilities::SerialForDevice(props[@"DADevicePath"]);
|
||||
serial = santa::SerialForDevice(props[@"DADevicePath"]);
|
||||
}
|
||||
|
||||
NSString *model = [NSString
|
||||
@@ -546,4 +768,4 @@ std::vector<uint8_t> BasicString::SerializeDiskDisappeared(NSDictionary *props)
|
||||
return FinalizeString(str);
|
||||
}
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#import "Source/common/SNTCachedDecision.h"
|
||||
#import "Source/common/SNTCommonEnums.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
@@ -36,24 +37,24 @@
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Serializer.h"
|
||||
#import "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::serializers::BasicString;
|
||||
using santa::santad::logs::endpoint_security::serializers::Serializer;
|
||||
using santa::BasicString;
|
||||
using santa::Enricher;
|
||||
using santa::Message;
|
||||
using santa::Serializer;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
extern std::string GetDecisionString(SNTEventState event_state);
|
||||
extern std::string GetReasonString(SNTEventState event_state);
|
||||
extern std::string GetModeString(SNTClientMode mode);
|
||||
extern std::string GetAccessTypeString(es_event_type_t event_type);
|
||||
extern std::string GetFileAccessPolicyDecisionString(FileAccessPolicyDecision decision);
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::logs::endpoint_security::serializers::GetAccessTypeString;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetDecisionString;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetFileAccessPolicyDecisionString;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetModeString;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetReasonString;
|
||||
using santa::GetAccessTypeString;
|
||||
using santa::GetDecisionString;
|
||||
using santa::GetFileAccessPolicyDecisionString;
|
||||
using santa::GetModeString;
|
||||
using santa::GetReasonString;
|
||||
|
||||
std::string BasicStringSerializeMessage(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg, SNTDecisionCache *decisionCache) {
|
||||
@@ -265,6 +266,248 @@ std::string BasicStringSerializeMessage(es_message_t *esMsg) {
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLogin {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN, &proc);
|
||||
es_event_lw_session_login_t lwLogin = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
esMsg.event.lw_session_login = &lwLogin;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=LOGIN_WINDOW_SESSION_LOGIN|pid=12|ppid=56|process=foo|processpath=foo|"
|
||||
"uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|"
|
||||
"graphical_session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLogout {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT, &proc);
|
||||
es_event_lw_session_logout_t lwLogout = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
esMsg.event.lw_session_logout = &lwLogout;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=LOGIN_WINDOW_SESSION_LOGOUT|pid=12|ppid=56|process=foo|processpath="
|
||||
"foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|"
|
||||
"graphical_session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLock {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK, &proc);
|
||||
es_event_lw_session_lock_t lwLock = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
esMsg.event.lw_session_lock = &lwLock;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=LOGIN_WINDOW_SESSION_LOCK|pid=12|ppid=56|process=foo|processpath=foo|"
|
||||
"uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|"
|
||||
"graphical_session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionUnlock {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK, &proc);
|
||||
es_event_lw_session_unlock_t lwUnlock = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
esMsg.event.lw_session_unlock = &lwUnlock;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=LOGIN_WINDOW_SESSION_UNLOCK|pid=12|ppid=56|process=foo|processpath="
|
||||
"foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_user=daemon|event_uid=1|"
|
||||
"graphical_session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginLogin {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN, &proc);
|
||||
es_event_login_login_t login = {
|
||||
.success = false,
|
||||
.failure_message = MakeESStringToken("my|failure"),
|
||||
.username = MakeESStringToken("asdf"),
|
||||
.has_uid = false,
|
||||
};
|
||||
esMsg.event.login_login = &login;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want =
|
||||
"action=LOGIN|success=false|failure=my<pipe>failure|pid=12|ppid=56|process=foo|processpath=foo|"
|
||||
"uid=-2|user=nobody|gid=-1|group=nogroup|event_user=asdf|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
|
||||
login.success = true;
|
||||
login.has_uid = true;
|
||||
login.uid.uid = 123;
|
||||
|
||||
got = BasicStringSerializeMessage(&esMsg);
|
||||
want = "action=LOGIN|success=true|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|"
|
||||
"gid=-1|group=nogroup|event_user=asdf|event_uid=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginLogout {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT, &proc);
|
||||
es_event_login_logout_t logout{
|
||||
.username = MakeESStringToken("asdf"),
|
||||
.uid = 123,
|
||||
};
|
||||
esMsg.event.login_logout = &logout;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=LOGOUT|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|"
|
||||
"gid=-1|group=nogroup|event_user=asdf|event_uid=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageScreenSharingAttach {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH, &proc);
|
||||
es_event_screensharing_attach_t attach{
|
||||
.success = true,
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV6,
|
||||
.source_address = MakeESStringToken("::1"),
|
||||
.viewer_appleid = MakeESStringToken("foo@example.com"),
|
||||
.authentication_type = MakeESStringToken("idk"),
|
||||
.authentication_username = MakeESStringToken("my_auth_user"),
|
||||
.session_username = MakeESStringToken("my_session_user"),
|
||||
.existing_session = true,
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
esMsg.event.screensharing_attach = &attach;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want =
|
||||
"action=SCREEN_SHARING_ATTACH|success=true|address_type=ipv6|address=::1|viewer=foo@example."
|
||||
"com|auth_type=idk|auth_user=my_auth_user|session_user=my_session_user|existing_session=true|"
|
||||
"pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|graphical_"
|
||||
"session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
|
||||
attach.source_address_type = (es_address_type_t)1234; // Intentionally bad
|
||||
attach.source_address = MakeESStringToken(NULL);
|
||||
attach.viewer_appleid = MakeESStringToken(NULL);
|
||||
attach.authentication_type = MakeESStringToken(NULL);
|
||||
attach.authentication_username = MakeESStringToken(NULL);
|
||||
attach.session_username = MakeESStringToken(NULL);
|
||||
|
||||
got = BasicStringSerializeMessage(&esMsg);
|
||||
want = "action=SCREEN_SHARING_ATTACH|success=true|address_type=unknown|existing_session=true|pid="
|
||||
"12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|graphical_"
|
||||
"session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageScreenSharingDetach {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH, &proc);
|
||||
es_event_screensharing_detach_t detach{
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV4,
|
||||
.source_address = MakeESStringToken("1.2.3.4"),
|
||||
.viewer_appleid = MakeESStringToken("foo@example.com"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
esMsg.event.screensharing_detach = &detach;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=SCREEN_SHARING_DETACH|address_type=ipv4|address=1.2.3.4|viewer=foo@"
|
||||
"example.com|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|"
|
||||
"gid=-1|group=nogroup|graphical_session_id=123|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageOpenSSHLogin {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN, &proc);
|
||||
es_event_openssh_login_t login{
|
||||
.success = false,
|
||||
.result_type = ES_OPENSSH_AUTH_FAIL_PASSWD,
|
||||
.source_address_type = ES_ADDRESS_TYPE_NAMED_SOCKET,
|
||||
.source_address = MakeESStringToken("foo"),
|
||||
.username = MakeESStringToken("my_user"),
|
||||
.has_uid = false,
|
||||
};
|
||||
esMsg.event.openssh_login = &login;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=OPENSSH_LOGIN|success=false|result_type=AUTH_FAIL_PASSWD|address_type="
|
||||
"named_socket|address=foo|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|"
|
||||
"user=nobody|gid=-1|group=nogroup|event_user=my_user|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
|
||||
login.success = true;
|
||||
login.result_type = ES_OPENSSH_AUTH_SUCCESS;
|
||||
login.has_uid = true;
|
||||
login.uid.uid = 456;
|
||||
|
||||
got = BasicStringSerializeMessage(&esMsg);
|
||||
want = "action=OPENSSH_LOGIN|success=true|result_type=AUTH_SUCCESS|address_type=named_socket|"
|
||||
"address=foo|pid=12|ppid=56|process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group="
|
||||
"nogroup|event_user=my_user|event_uid=456|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageOpenSSHLogout {
|
||||
es_file_t procFile = MakeESFile("foo");
|
||||
es_process_t proc = MakeESProcess(&procFile, MakeAuditToken(12, 34), MakeAuditToken(56, 78));
|
||||
es_message_t esMsg = MakeESMessage(ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT, &proc);
|
||||
es_event_openssh_logout_t logout{
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV4,
|
||||
.source_address = MakeESStringToken("5.6.7.8"),
|
||||
.username = MakeESStringToken("my_user"),
|
||||
.uid = 321,
|
||||
};
|
||||
esMsg.event.openssh_logout = &logout;
|
||||
|
||||
std::string got = BasicStringSerializeMessage(&esMsg);
|
||||
std::string want = "action=OPENSSH_LOGOUT|address_type=ipv4|address=5.6.7.8|pid=12|ppid=56|"
|
||||
"process=foo|processpath=foo|uid=-2|user=nobody|gid=-1|group=nogroup|event_"
|
||||
"user=my_user|event_uid=321|machineid=my_id\n";
|
||||
|
||||
XCTAssertCppStringEqual(got, want);
|
||||
}
|
||||
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
- (void)testGetAccessTypeString {
|
||||
std::map<es_event_type_t, std::string> accessTypeToString = {
|
||||
{ES_EVENT_TYPE_AUTH_OPEN, "OPEN"}, {ES_EVENT_TYPE_AUTH_LINK, "LINK"},
|
||||
|
||||
@@ -23,42 +23,41 @@
|
||||
#include "Source/common/SNTCachedDecision.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Serializer.h"
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
class Empty : public Serializer {
|
||||
public:
|
||||
static std::shared_ptr<Empty> Create();
|
||||
Empty();
|
||||
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExec &,
|
||||
SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExec &, SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedCSInvalidated &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionUnlock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingAttach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingDetach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogout &) override;
|
||||
|
||||
std::vector<uint8_t> SerializeFileAccess(
|
||||
const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision) override;
|
||||
std::vector<uint8_t> SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name,
|
||||
const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target,
|
||||
FileAccessPolicyDecision decision) override;
|
||||
|
||||
std::vector<uint8_t> SerializeAllowlist(
|
||||
const santa::santad::event_providers::endpoint_security::Message &,
|
||||
const std::string_view) override;
|
||||
std::vector<uint8_t> SerializeAllowlist(const santa::Message &, const std::string_view) override;
|
||||
|
||||
std::vector<uint8_t> SerializeBundleHashingEvent(SNTStoredEvent *) override;
|
||||
|
||||
@@ -66,6 +65,6 @@ class Empty : public Serializer {
|
||||
std::vector<uint8_t> SerializeDiskDisappeared(NSDictionary *) override;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,19 +14,29 @@
|
||||
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Empty.h"
|
||||
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedClose;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExchange;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExec;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExit;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFork;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedLink;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedRename;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedUnlink;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::EnrichedClose;
|
||||
using santa::EnrichedCSInvalidated;
|
||||
using santa::EnrichedExchange;
|
||||
using santa::EnrichedExec;
|
||||
using santa::EnrichedExit;
|
||||
using santa::EnrichedFork;
|
||||
using santa::EnrichedLink;
|
||||
using santa::EnrichedLoginLogin;
|
||||
using santa::EnrichedLoginLogout;
|
||||
using santa::EnrichedLoginWindowSessionLock;
|
||||
using santa::EnrichedLoginWindowSessionLogin;
|
||||
using santa::EnrichedLoginWindowSessionLogout;
|
||||
using santa::EnrichedLoginWindowSessionUnlock;
|
||||
using santa::EnrichedOpenSSHLogin;
|
||||
using santa::EnrichedOpenSSHLogout;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::EnrichedRename;
|
||||
using santa::EnrichedScreenSharingAttach;
|
||||
using santa::EnrichedScreenSharingDetach;
|
||||
using santa::EnrichedUnlink;
|
||||
using santa::Message;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
std::shared_ptr<Empty> Empty::Create() {
|
||||
return std::make_shared<Empty>();
|
||||
@@ -70,6 +80,46 @@ std::vector<uint8_t> Empty::SerializeMessage(const EnrichedCSInvalidated &msg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginWindowSessionLogin &msg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginWindowSessionLogout &msg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginWindowSessionLock &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginWindowSessionUnlock &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedScreenSharingAttach &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedScreenSharingDetach &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedOpenSSHLogin &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedOpenSSHLogout &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginLogin &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeMessage(const EnrichedLoginLogout &) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Empty::SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name, const Message &msg,
|
||||
const EnrichedProcess &enriched_process,
|
||||
@@ -94,4 +144,4 @@ std::vector<uint8_t> Empty::SerializeDiskDisappeared(NSDictionary *props) {
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EnrichedTypes.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Empty.h"
|
||||
|
||||
using santa::santad::logs::endpoint_security::serializers::Empty;
|
||||
|
||||
namespace es = santa::santad::event_providers::endpoint_security;
|
||||
using santa::Empty;
|
||||
|
||||
@interface EmptyTest : XCTestCase
|
||||
@end
|
||||
@@ -35,17 +33,17 @@ namespace es = santa::santad::event_providers::endpoint_security;
|
||||
// instead of constructing real ones since the Empty class never touches the
|
||||
// input parameter.
|
||||
int fake;
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedClose *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedExchange *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedExec *)&fake, nil).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedExit *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedFork *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedLink *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedRename *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedUnlink *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(es::EnrichedCSInvalidated *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedClose *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedExchange *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedExec *)&fake, nil).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedExit *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedFork *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedLink *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedRename *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedUnlink *)&fake).size(), 0);
|
||||
XCTAssertEqual(e->SerializeMessage(*(santa::EnrichedCSInvalidated *)&fake).size(), 0);
|
||||
|
||||
XCTAssertEqual(e->SerializeAllowlist(*(es::Message *)&fake, "").size(), 0);
|
||||
XCTAssertEqual(e->SerializeAllowlist(*(santa::Message *)&fake, "").size(), 0);
|
||||
XCTAssertEqual(e->SerializeBundleHashingEvent(nil).size(), 0);
|
||||
XCTAssertEqual(e->SerializeDiskAppeared(nil).size(), 0);
|
||||
XCTAssertEqual(e->SerializeDiskDisappeared(nil).size(), 0);
|
||||
|
||||
@@ -21,53 +21,53 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#import "Source/common/SNTCachedDecision.h"
|
||||
#include "Source/common/santa_proto_include_wrapper.h"
|
||||
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
|
||||
#include "Source/santad/Logs/EndpointSecurity/Serializers/Serializer.h"
|
||||
#import "Source/santad/SNTDecisionCache.h"
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
class Protobuf : public Serializer {
|
||||
public:
|
||||
static std::shared_ptr<Protobuf> Create(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache, bool json = false);
|
||||
static std::shared_ptr<Protobuf> Create(std::shared_ptr<santa::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache, bool json = false);
|
||||
|
||||
Protobuf(
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
|
||||
SNTDecisionCache *decision_cache, bool json = false);
|
||||
Protobuf(std::shared_ptr<santa::EndpointSecurityAPI> esapi, SNTDecisionCache *decision_cache,
|
||||
bool json = false);
|
||||
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExec &,
|
||||
SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedClose &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExchange &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExec &, SNTCachedDecision *) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedExit &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedFork &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedRename &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedUnlink &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedCSInvalidated &) override;
|
||||
#if HAVE_MACOS_13
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionLock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginWindowSessionUnlock &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingAttach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedScreenSharingDetach &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedOpenSSHLogout &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogin &) override;
|
||||
std::vector<uint8_t> SerializeMessage(const santa::EnrichedLoginLogout &) override;
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> SerializeFileAccess(
|
||||
const std::string &policy_version, const std::string &policy_name,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedProcess &enriched_process,
|
||||
const std::string &target, FileAccessPolicyDecision decision) override;
|
||||
std::vector<uint8_t> SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name,
|
||||
const santa::Message &msg,
|
||||
const santa::EnrichedProcess &enriched_process,
|
||||
const std::string &target,
|
||||
FileAccessPolicyDecision decision) override;
|
||||
|
||||
std::vector<uint8_t> SerializeAllowlist(
|
||||
const santa::santad::event_providers::endpoint_security::Message &,
|
||||
const std::string_view) override;
|
||||
std::vector<uint8_t> SerializeAllowlist(const santa::Message &, const std::string_view) override;
|
||||
|
||||
std::vector<uint8_t> SerializeBundleHashingEvent(SNTStoredEvent *) override;
|
||||
|
||||
@@ -76,24 +76,22 @@ class Protobuf : public Serializer {
|
||||
|
||||
private:
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(google::protobuf::Arena *arena);
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(
|
||||
google::protobuf::Arena *arena,
|
||||
const santa::santad::event_providers::endpoint_security::EnrichedEventType &msg);
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(
|
||||
google::protobuf::Arena *arena,
|
||||
const santa::santad::event_providers::endpoint_security::Message &msg);
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(google::protobuf::Arena *arena,
|
||||
const santa::EnrichedEventType &msg);
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(google::protobuf::Arena *arena,
|
||||
const santa::Message &msg);
|
||||
::santa::pb::v1::SantaMessage *CreateDefaultProto(google::protobuf::Arena *arena,
|
||||
struct timespec event_time,
|
||||
struct timespec processed_time);
|
||||
|
||||
std::vector<uint8_t> FinalizeProto(::santa::pb::v1::SantaMessage *santa_msg);
|
||||
|
||||
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi_;
|
||||
std::shared_ptr<santa::EndpointSecurityAPI> esapi_;
|
||||
// Toggle for transforming protobuf output to its JSON form.
|
||||
// See https://protobuf.dev/programming-guides/proto3/#json
|
||||
bool json_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,33 +43,44 @@ using google::protobuf::Timestamp;
|
||||
using JsonPrintOptions = google::protobuf::json::PrintOptions;
|
||||
using google::protobuf::json::MessageToJsonString;
|
||||
|
||||
using santa::common::NSStringToUTF8StringView;
|
||||
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedClose;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedCSInvalidated;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedEventType;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExchange;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExec;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedExit;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFile;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedFork;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedLink;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedProcess;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedRename;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedUnlink;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::EffectiveGroup;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::EffectiveUser;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::MountFromName;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::NonNull;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::Pid;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::Pidversion;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::RealGroup;
|
||||
using santa::santad::logs::endpoint_security::serializers::Utilities::RealUser;
|
||||
using santa::EffectiveGroup;
|
||||
using santa::EffectiveUser;
|
||||
using santa::EndpointSecurityAPI;
|
||||
using santa::EnrichedClose;
|
||||
using santa::EnrichedCSInvalidated;
|
||||
using santa::EnrichedEventType;
|
||||
using santa::EnrichedExchange;
|
||||
using santa::EnrichedExec;
|
||||
using santa::EnrichedExit;
|
||||
using santa::EnrichedFile;
|
||||
using santa::EnrichedFork;
|
||||
using santa::EnrichedLink;
|
||||
using santa::EnrichedLoginLogin;
|
||||
using santa::EnrichedLoginLogout;
|
||||
using santa::EnrichedLoginWindowSessionLock;
|
||||
using santa::EnrichedLoginWindowSessionLogin;
|
||||
using santa::EnrichedLoginWindowSessionLogout;
|
||||
using santa::EnrichedLoginWindowSessionUnlock;
|
||||
using santa::EnrichedOpenSSHLogin;
|
||||
using santa::EnrichedOpenSSHLogout;
|
||||
using santa::EnrichedProcess;
|
||||
using santa::EnrichedRename;
|
||||
using santa::EnrichedScreenSharingAttach;
|
||||
using santa::EnrichedScreenSharingDetach;
|
||||
using santa::EnrichedUnlink;
|
||||
using santa::Message;
|
||||
using santa::MountFromName;
|
||||
using santa::NonNull;
|
||||
using santa::NSStringToUTF8StringView;
|
||||
using santa::Pid;
|
||||
using santa::Pidversion;
|
||||
using santa::RealGroup;
|
||||
using santa::RealUser;
|
||||
using santa::StringTokenToStringView;
|
||||
|
||||
namespace pbv1 = ::santa::pb::v1;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
static constexpr NSUInteger kMaxEncodeObjectEntries = 64;
|
||||
static constexpr NSUInteger kMaxEncodeObjectLevels = 5;
|
||||
@@ -128,6 +139,16 @@ static inline void EncodeUserInfo(::pbv1::UserInfo *pb_user_info, uid_t uid,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void EncodeUserInfo(std::function<::pbv1::UserInfo *()> lazy_f,
|
||||
std::optional<uid_t> uid, const es_string_token_t &name) {
|
||||
if (uid.has_value()) {
|
||||
lazy_f()->set_uid(uid.value());
|
||||
}
|
||||
if (name.length > 0) {
|
||||
lazy_f()->set_name(name.data, name.length);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void EncodeGroupInfo(::pbv1::GroupInfo *pb_group_info, gid_t gid,
|
||||
const std::optional<std::shared_ptr<std::string>> &name) {
|
||||
pb_group_info->set_gid(gid);
|
||||
@@ -194,7 +215,7 @@ static inline void EncodeAnnotations(std::function<::pbv1::process_tree::Annotat
|
||||
}
|
||||
|
||||
static inline void EncodeProcessInfoLight(::pbv1::ProcessInfoLight *pb_proc_info,
|
||||
uint32_t message_version, const es_process_t *es_proc,
|
||||
const es_process_t *es_proc,
|
||||
const EnrichedProcess &enriched_proc) {
|
||||
EncodeProcessID(pb_proc_info->mutable_id(), es_proc->audit_token);
|
||||
EncodeProcessID(pb_proc_info->mutable_parent_id(), es_proc->parent_audit_token);
|
||||
@@ -217,6 +238,11 @@ static inline void EncodeProcessInfoLight(::pbv1::ProcessInfoLight *pb_proc_info
|
||||
EncodeAnnotations([pb_proc_info] { return pb_proc_info->mutable_annotations(); }, enriched_proc);
|
||||
}
|
||||
|
||||
static inline void EncodeProcessInfoLight(::pbv1::ProcessInfoLight *pb_proc_info,
|
||||
const EnrichedEventType &msg) {
|
||||
return EncodeProcessInfoLight(pb_proc_info, msg->process, msg.instigator());
|
||||
}
|
||||
|
||||
static inline void EncodeProcessInfo(::pbv1::ProcessInfo *pb_proc_info, uint32_t message_version,
|
||||
const es_process_t *es_proc,
|
||||
const EnrichedProcess &enriched_proc,
|
||||
@@ -393,7 +419,7 @@ static inline void EncodeCertificateInfo(::pbv1::CertificateInfo *pb_cert_info,
|
||||
}
|
||||
|
||||
::pbv1::SantaMessage *Protobuf::CreateDefaultProto(Arena *arena, const EnrichedEventType &msg) {
|
||||
return CreateDefaultProto(arena, msg.es_msg().time, msg.enrichment_time());
|
||||
return CreateDefaultProto(arena, msg->time, msg.enrichment_time());
|
||||
}
|
||||
|
||||
::pbv1::SantaMessage *Protobuf::CreateDefaultProto(Arena *arena, const Message &msg) {
|
||||
@@ -442,10 +468,9 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedClose &msg) {
|
||||
|
||||
::pbv1::Close *pb_close = santa_msg->mutable_close();
|
||||
|
||||
EncodeProcessInfoLight(pb_close->mutable_instigator(), msg.es_msg().version, msg.es_msg().process,
|
||||
msg.instigator());
|
||||
EncodeFileInfo(pb_close->mutable_target(), msg.es_msg().event.close.target, msg.target());
|
||||
pb_close->set_modified(msg.es_msg().event.close.modified);
|
||||
EncodeProcessInfoLight(pb_close->mutable_instigator(), msg);
|
||||
EncodeFileInfo(pb_close->mutable_target(), msg->event.close.target, msg.target());
|
||||
pb_close->set_modified(msg->event.close.modified);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -456,12 +481,9 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedExchange &msg) {
|
||||
|
||||
::pbv1::Exchangedata *pb_exchangedata = santa_msg->mutable_exchangedata();
|
||||
|
||||
EncodeProcessInfoLight(pb_exchangedata->mutable_instigator(), msg.es_msg().version,
|
||||
msg.es_msg().process, msg.instigator());
|
||||
EncodeFileInfo(pb_exchangedata->mutable_file1(), msg.es_msg().event.exchangedata.file1,
|
||||
msg.file1());
|
||||
EncodeFileInfo(pb_exchangedata->mutable_file2(), msg.es_msg().event.exchangedata.file2,
|
||||
msg.file2());
|
||||
EncodeProcessInfoLight(pb_exchangedata->mutable_instigator(), msg);
|
||||
EncodeFileInfo(pb_exchangedata->mutable_file1(), msg->event.exchangedata.file1, msg.file1());
|
||||
EncodeFileInfo(pb_exchangedata->mutable_file2(), msg->event.exchangedata.file2, msg.file2());
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -592,45 +614,44 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedExec &msg, SNTCach
|
||||
|
||||
::pbv1::Execution *pb_exec = santa_msg->mutable_execution();
|
||||
|
||||
EncodeProcessInfoLight(pb_exec->mutable_instigator(), msg.es_msg().version, msg.es_msg().process,
|
||||
msg.instigator());
|
||||
EncodeProcessInfo(pb_exec->mutable_target(), msg.es_msg().version, msg.es_msg().event.exec.target,
|
||||
msg.target(), cd);
|
||||
EncodeProcessInfoLight(pb_exec->mutable_instigator(), msg);
|
||||
EncodeProcessInfo(pb_exec->mutable_target(), msg->version, msg->event.exec.target, msg.target(),
|
||||
cd);
|
||||
|
||||
if (msg.es_msg().version >= 2 && msg.script().has_value()) {
|
||||
EncodeFileInfo(pb_exec->mutable_script(), msg.es_msg().event.exec.script, msg.script().value());
|
||||
if (msg->version >= 2 && msg.script().has_value()) {
|
||||
EncodeFileInfo(pb_exec->mutable_script(), msg->event.exec.script, msg.script().value());
|
||||
}
|
||||
|
||||
if (msg.es_msg().version >= 3 && msg.working_dir().has_value()) {
|
||||
EncodeFileInfo(pb_exec->mutable_working_directory(), msg.es_msg().event.exec.cwd,
|
||||
if (msg->version >= 3 && msg.working_dir().has_value()) {
|
||||
EncodeFileInfo(pb_exec->mutable_working_directory(), msg->event.exec.cwd,
|
||||
msg.working_dir().value());
|
||||
}
|
||||
|
||||
uint32_t arg_count = esapi_->ExecArgCount(&msg.es_msg().event.exec);
|
||||
uint32_t arg_count = esapi_->ExecArgCount(&msg->event.exec);
|
||||
if (arg_count > 0) {
|
||||
pb_exec->mutable_args()->Reserve(arg_count);
|
||||
for (uint32_t i = 0; i < arg_count; i++) {
|
||||
es_string_token_t tok = esapi_->ExecArg(&msg.es_msg().event.exec, i);
|
||||
es_string_token_t tok = esapi_->ExecArg(&msg->event.exec, i);
|
||||
pb_exec->add_args(tok.data, tok.length);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t env_count = esapi_->ExecEnvCount(&msg.es_msg().event.exec);
|
||||
uint32_t env_count = esapi_->ExecEnvCount(&msg->event.exec);
|
||||
if (env_count > 0) {
|
||||
pb_exec->mutable_envs()->Reserve(env_count);
|
||||
for (uint32_t i = 0; i < env_count; i++) {
|
||||
es_string_token_t tok = esapi_->ExecEnv(&msg.es_msg().event.exec, i);
|
||||
es_string_token_t tok = esapi_->ExecEnv(&msg->event.exec, i);
|
||||
pb_exec->add_envs(tok.data, tok.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.es_msg().version >= 4) {
|
||||
if (msg->version >= 4) {
|
||||
int32_t max_fd = -1;
|
||||
uint32_t fd_count = esapi_->ExecFDCount(&msg.es_msg().event.exec);
|
||||
uint32_t fd_count = esapi_->ExecFDCount(&msg->event.exec);
|
||||
if (fd_count > 0) {
|
||||
pb_exec->mutable_fds()->Reserve(fd_count);
|
||||
for (uint32_t i = 0; i < fd_count; i++) {
|
||||
const es_fd_t *fd = esapi_->ExecFD(&msg.es_msg().event.exec, i);
|
||||
const es_fd_t *fd = esapi_->ExecFD(&msg->event.exec, i);
|
||||
max_fd = std::max(max_fd, fd->fd);
|
||||
::pbv1::FileDescriptor *pb_fd = pb_exec->add_fds();
|
||||
pb_fd->set_fd(fd->fd);
|
||||
@@ -643,7 +664,7 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedExec &msg, SNTCach
|
||||
|
||||
// If the `max_fd` seen is less than `last_fd`, we know that ES truncated
|
||||
// the set of returned file descriptors
|
||||
pb_exec->set_fd_list_truncated(max_fd < msg.es_msg().event.exec.last_fd);
|
||||
pb_exec->set_fd_list_truncated(max_fd < msg->event.exec.last_fd);
|
||||
}
|
||||
|
||||
pb_exec->set_decision(GetDecisionEnum(cd.decision));
|
||||
@@ -657,7 +678,7 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedExec &msg, SNTCach
|
||||
EncodeString([pb_exec] { return pb_exec->mutable_explain(); }, cd.decisionExtra);
|
||||
EncodeString([pb_exec] { return pb_exec->mutable_quarantine_url(); }, cd.quarantineURL);
|
||||
|
||||
NSString *orig_path = Utilities::OriginalPathForTranslocation(msg.es_msg().event.exec.target);
|
||||
NSString *orig_path = santa::OriginalPathForTranslocation(msg->event.exec.target);
|
||||
EncodeString([pb_exec] { return pb_exec->mutable_original_path(); }, orig_path);
|
||||
|
||||
EncodeEntitlements(pb_exec, cd);
|
||||
@@ -671,9 +692,8 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedExit &msg) {
|
||||
|
||||
::pbv1::Exit *pb_exit = santa_msg->mutable_exit();
|
||||
|
||||
EncodeProcessInfoLight(pb_exit->mutable_instigator(), msg.es_msg().version, msg.es_msg().process,
|
||||
msg.instigator());
|
||||
EncodeExitStatus(pb_exit, msg.es_msg().event.exit.stat);
|
||||
EncodeProcessInfoLight(pb_exit->mutable_instigator(), msg);
|
||||
EncodeExitStatus(pb_exit, msg->event.exit.stat);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -684,10 +704,8 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedFork &msg) {
|
||||
|
||||
::pbv1::Fork *pb_fork = santa_msg->mutable_fork();
|
||||
|
||||
EncodeProcessInfoLight(pb_fork->mutable_instigator(), msg.es_msg().version, msg.es_msg().process,
|
||||
msg.instigator());
|
||||
EncodeProcessInfoLight(pb_fork->mutable_child(), msg.es_msg().version,
|
||||
msg.es_msg().event.fork.child, msg.child());
|
||||
EncodeProcessInfoLight(pb_fork->mutable_instigator(), msg);
|
||||
EncodeProcessInfoLight(pb_fork->mutable_child(), msg->event.fork.child, msg.child());
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -697,11 +715,10 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLink &msg) {
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
|
||||
::pbv1::Link *pb_link = santa_msg->mutable_link();
|
||||
EncodeProcessInfoLight(pb_link->mutable_instigator(), msg.es_msg().version, msg.es_msg().process,
|
||||
msg.instigator());
|
||||
EncodeFileInfo(pb_link->mutable_source(), msg.es_msg().event.link.source, msg.source());
|
||||
EncodePath(pb_link->mutable_target(), msg.es_msg().event.link.target_dir,
|
||||
msg.es_msg().event.link.target_filename);
|
||||
EncodeProcessInfoLight(pb_link->mutable_instigator(), msg);
|
||||
EncodeFileInfo(pb_link->mutable_source(), msg->event.link.source, msg.source());
|
||||
EncodePath(pb_link->mutable_target(), msg->event.link.target_dir,
|
||||
msg->event.link.target_filename);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -711,15 +728,14 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedRename &msg) {
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
|
||||
::pbv1::Rename *pb_rename = santa_msg->mutable_rename();
|
||||
EncodeProcessInfoLight(pb_rename->mutable_instigator(), msg.es_msg().version,
|
||||
msg.es_msg().process, msg.instigator());
|
||||
EncodeFileInfo(pb_rename->mutable_source(), msg.es_msg().event.rename.source, msg.source());
|
||||
if (msg.es_msg().event.rename.destination_type == ES_DESTINATION_TYPE_EXISTING_FILE) {
|
||||
EncodePath(pb_rename->mutable_target(), msg.es_msg().event.rename.destination.existing_file);
|
||||
EncodeProcessInfoLight(pb_rename->mutable_instigator(), msg);
|
||||
EncodeFileInfo(pb_rename->mutable_source(), msg->event.rename.source, msg.source());
|
||||
if (msg->event.rename.destination_type == ES_DESTINATION_TYPE_EXISTING_FILE) {
|
||||
EncodePath(pb_rename->mutable_target(), msg->event.rename.destination.existing_file);
|
||||
pb_rename->set_target_existed(true);
|
||||
} else {
|
||||
EncodePath(pb_rename->mutable_target(), msg.es_msg().event.rename.destination.new_path.dir,
|
||||
msg.es_msg().event.rename.destination.new_path.filename);
|
||||
EncodePath(pb_rename->mutable_target(), msg->event.rename.destination.new_path.dir,
|
||||
msg->event.rename.destination.new_path.filename);
|
||||
pb_rename->set_target_existed(false);
|
||||
}
|
||||
|
||||
@@ -731,9 +747,8 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedUnlink &msg) {
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
|
||||
::pbv1::Unlink *pb_unlink = santa_msg->mutable_unlink();
|
||||
EncodeProcessInfoLight(pb_unlink->mutable_instigator(), msg.es_msg().version,
|
||||
msg.es_msg().process, msg.instigator());
|
||||
EncodeFileInfo(pb_unlink->mutable_target(), msg.es_msg().event.unlink.target, msg.target());
|
||||
EncodeProcessInfoLight(pb_unlink->mutable_instigator(), msg);
|
||||
EncodeFileInfo(pb_unlink->mutable_target(), msg->event.unlink.target, msg.target());
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
@@ -743,12 +758,230 @@ std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedCSInvalidated &msg
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
|
||||
::pbv1::CodesigningInvalidated *pb_cs_invalidated = santa_msg->mutable_codesigning_invalidated();
|
||||
EncodeProcessInfoLight(pb_cs_invalidated->mutable_instigator(), msg.es_msg().version,
|
||||
msg.es_msg().process, msg.instigator());
|
||||
EncodeProcessInfoLight(pb_cs_invalidated->mutable_instigator(), msg);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
|
||||
::pbv1::SocketAddress::Type GetSocketAddressType(es_address_type_t type) {
|
||||
switch (type) {
|
||||
case ES_ADDRESS_TYPE_NONE: return ::pbv1::SocketAddress::TYPE_NONE;
|
||||
case ES_ADDRESS_TYPE_IPV4: return ::pbv1::SocketAddress::TYPE_IPV4;
|
||||
case ES_ADDRESS_TYPE_IPV6: return ::pbv1::SocketAddress::TYPE_IPV6;
|
||||
case ES_ADDRESS_TYPE_NAMED_SOCKET: return ::pbv1::SocketAddress::TYPE_NAMED_SOCKET;
|
||||
default: return ::pbv1::SocketAddress::TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
::pbv1::OpenSSHLogin::Result GetOpenSSHLoginResultType(es_openssh_login_result_type_t type) {
|
||||
switch (type) {
|
||||
case ES_OPENSSH_LOGIN_EXCEED_MAXTRIES:
|
||||
return ::pbv1::OpenSSHLogin::RESULT_LOGIN_EXCEED_MAXTRIES;
|
||||
case ES_OPENSSH_LOGIN_ROOT_DENIED: return ::pbv1::OpenSSHLogin::RESULT_LOGIN_ROOT_DENIED;
|
||||
case ES_OPENSSH_AUTH_SUCCESS: return ::pbv1::OpenSSHLogin::RESULT_AUTH_SUCCESS;
|
||||
case ES_OPENSSH_AUTH_FAIL_NONE: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_NONE;
|
||||
case ES_OPENSSH_AUTH_FAIL_PASSWD: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_PASSWD;
|
||||
case ES_OPENSSH_AUTH_FAIL_KBDINT: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_KBDINT;
|
||||
case ES_OPENSSH_AUTH_FAIL_PUBKEY: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_PUBKEY;
|
||||
case ES_OPENSSH_AUTH_FAIL_HOSTBASED: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_HOSTBASED;
|
||||
case ES_OPENSSH_AUTH_FAIL_GSSAPI: return ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_GSSAPI;
|
||||
case ES_OPENSSH_INVALID_USER: return ::pbv1::OpenSSHLogin::RESULT_INVALID_USER;
|
||||
default: return ::pbv1::OpenSSHLogin::RESULT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void EncodeSocketAddress(::pbv1::SocketAddress *pb_socket_addr, std::string_view addr,
|
||||
es_address_type_t type) {
|
||||
EncodeString([pb_socket_addr] { return pb_socket_addr->mutable_address(); }, addr);
|
||||
pb_socket_addr->set_type(GetSocketAddressType(type));
|
||||
}
|
||||
|
||||
static inline void EncodeUserInfo(std::function<::pbv1::UserInfo *()> lazy_f,
|
||||
const es_string_token_t &name) {
|
||||
EncodeUserInfo(lazy_f, std::nullopt, name);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginWindowSessionLogin &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::LoginWindowSessionLogin *pb_lw_login =
|
||||
santa_msg->mutable_login_window_session()->mutable_login();
|
||||
|
||||
EncodeProcessInfoLight(pb_lw_login->mutable_instigator(), msg);
|
||||
EncodeUserInfo([pb_lw_login] { return pb_lw_login->mutable_user(); }, msg.UID(),
|
||||
msg->event.lw_session_login->username);
|
||||
|
||||
pb_lw_login->mutable_graphical_session()->set_id(
|
||||
msg->event.lw_session_login->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginWindowSessionLogout &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::LoginWindowSessionLogout *pb_lw_logout =
|
||||
santa_msg->mutable_login_window_session()->mutable_logout();
|
||||
|
||||
EncodeProcessInfoLight(pb_lw_logout->mutable_instigator(), msg);
|
||||
EncodeUserInfo([pb_lw_logout] { return pb_lw_logout->mutable_user(); }, msg.UID(),
|
||||
msg->event.lw_session_logout->username);
|
||||
|
||||
pb_lw_logout->mutable_graphical_session()->set_id(
|
||||
msg->event.lw_session_logout->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginWindowSessionLock &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::LoginWindowSessionLock *pb_lw_lock =
|
||||
santa_msg->mutable_login_window_session()->mutable_lock();
|
||||
|
||||
EncodeProcessInfoLight(pb_lw_lock->mutable_instigator(), msg);
|
||||
EncodeUserInfo([pb_lw_lock] { return pb_lw_lock->mutable_user(); }, msg.UID(),
|
||||
msg->event.lw_session_lock->username);
|
||||
|
||||
pb_lw_lock->mutable_graphical_session()->set_id(msg->event.lw_session_lock->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginWindowSessionUnlock &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::LoginWindowSessionUnlock *pb_lw_unlock =
|
||||
santa_msg->mutable_login_window_session()->mutable_unlock();
|
||||
|
||||
EncodeProcessInfoLight(pb_lw_unlock->mutable_instigator(), msg);
|
||||
EncodeUserInfo([pb_lw_unlock] { return pb_lw_unlock->mutable_user(); }, msg.UID(),
|
||||
msg->event.lw_session_unlock->username);
|
||||
|
||||
pb_lw_unlock->mutable_graphical_session()->set_id(
|
||||
msg->event.lw_session_unlock->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedScreenSharingAttach &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::ScreenSharingAttach *pb_attach = santa_msg->mutable_screen_sharing()->mutable_attach();
|
||||
|
||||
EncodeProcessInfoLight(pb_attach->mutable_instigator(), msg);
|
||||
|
||||
pb_attach->set_success(msg->event.screensharing_attach->success);
|
||||
|
||||
EncodeSocketAddress(pb_attach->mutable_source(),
|
||||
StringTokenToStringView(msg->event.screensharing_attach->source_address),
|
||||
msg->event.screensharing_attach->source_address_type);
|
||||
EncodeString([pb_attach] { return pb_attach->mutable_viewer(); },
|
||||
StringTokenToStringView(msg->event.screensharing_attach->viewer_appleid));
|
||||
EncodeString([pb_attach] { return pb_attach->mutable_authentication_type(); },
|
||||
StringTokenToStringView(msg->event.screensharing_attach->authentication_type));
|
||||
EncodeUserInfo([pb_attach] { return pb_attach->mutable_authentication_user(); },
|
||||
msg->event.screensharing_attach->authentication_username);
|
||||
EncodeUserInfo([pb_attach] { return pb_attach->mutable_session_user(); },
|
||||
msg->event.screensharing_attach->session_username);
|
||||
|
||||
pb_attach->set_existing_session(msg->event.screensharing_attach->existing_session);
|
||||
pb_attach->mutable_graphical_session()->set_id(
|
||||
msg->event.screensharing_attach->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedScreenSharingDetach &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::ScreenSharingDetach *pb_detach = santa_msg->mutable_screen_sharing()->mutable_detach();
|
||||
|
||||
EncodeProcessInfoLight(pb_detach->mutable_instigator(), msg);
|
||||
EncodeSocketAddress(pb_detach->mutable_source(),
|
||||
StringTokenToStringView(msg->event.screensharing_detach->source_address),
|
||||
msg->event.screensharing_detach->source_address_type);
|
||||
EncodeString([pb_detach] { return pb_detach->mutable_viewer(); },
|
||||
StringTokenToStringView(msg->event.screensharing_detach->viewer_appleid));
|
||||
|
||||
pb_detach->mutable_graphical_session()->set_id(
|
||||
msg->event.screensharing_detach->graphical_session_id);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedOpenSSHLogin &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::OpenSSHLogin *pb_ssh_login = santa_msg->mutable_open_ssh()->mutable_login();
|
||||
|
||||
EncodeProcessInfoLight(pb_ssh_login->mutable_instigator(), msg);
|
||||
|
||||
pb_ssh_login->set_result(GetOpenSSHLoginResultType(msg->event.openssh_login->result_type));
|
||||
|
||||
EncodeSocketAddress(pb_ssh_login->mutable_source(),
|
||||
StringTokenToStringView(msg->event.openssh_login->source_address),
|
||||
msg->event.openssh_login->source_address_type);
|
||||
EncodeUserInfo([pb_ssh_login] { return pb_ssh_login->mutable_user(); },
|
||||
msg->event.openssh_login->has_uid
|
||||
? std::make_optional<uid_t>(msg->event.openssh_login->uid.uid)
|
||||
: std::nullopt,
|
||||
msg->event.openssh_login->username);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedOpenSSHLogout &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::OpenSSHLogout *pb_ssh_logout = santa_msg->mutable_open_ssh()->mutable_logout();
|
||||
|
||||
EncodeProcessInfoLight(pb_ssh_logout->mutable_instigator(), msg);
|
||||
|
||||
EncodeSocketAddress(pb_ssh_logout->mutable_source(),
|
||||
StringTokenToStringView(msg->event.openssh_logout->source_address),
|
||||
msg->event.openssh_logout->source_address_type);
|
||||
EncodeUserInfo([pb_ssh_logout] { return pb_ssh_logout->mutable_user(); },
|
||||
msg->event.openssh_logout->uid, msg->event.openssh_logout->username);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginLogin &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::Login *pb_login = santa_msg->mutable_login_logout()->mutable_login();
|
||||
|
||||
EncodeProcessInfoLight(pb_login->mutable_instigator(), msg);
|
||||
pb_login->set_success(msg->event.login_login->success);
|
||||
|
||||
EncodeString([pb_login] { return pb_login->mutable_failure_message(); },
|
||||
StringTokenToStringView(msg->event.login_login->failure_message));
|
||||
EncodeUserInfo([pb_login] { return pb_login->mutable_user(); },
|
||||
msg->event.login_login->has_uid
|
||||
? std::make_optional<uid_t>(msg->event.login_login->uid.uid)
|
||||
: std::nullopt,
|
||||
msg->event.login_login->username);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeMessage(const EnrichedLoginLogout &msg) {
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena, msg);
|
||||
::pbv1::Logout *pb_logout = santa_msg->mutable_login_logout()->mutable_logout();
|
||||
|
||||
EncodeProcessInfoLight(pb_logout->mutable_instigator(), msg);
|
||||
EncodeUserInfo([pb_logout] { return pb_logout->mutable_user(); }, msg->event.login_logout->uid,
|
||||
msg->event.login_logout->username);
|
||||
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
std::vector<uint8_t> Protobuf::SerializeFileAccess(const std::string &policy_version,
|
||||
const std::string &policy_name,
|
||||
const Message &msg,
|
||||
@@ -776,14 +1009,13 @@ std::vector<uint8_t> Protobuf::SerializeAllowlist(const Message &msg, const std:
|
||||
Arena arena;
|
||||
::pbv1::SantaMessage *santa_msg = CreateDefaultProto(&arena);
|
||||
|
||||
const es_file_t *es_file = Utilities::GetAllowListTargetFile(msg);
|
||||
const es_file_t *es_file = santa::GetAllowListTargetFile(msg);
|
||||
|
||||
EnrichedFile enriched_file(std::nullopt, std::nullopt, std::nullopt);
|
||||
EnrichedProcess enriched_process;
|
||||
|
||||
::pbv1::Allowlist *pb_allowlist = santa_msg->mutable_allowlist();
|
||||
EncodeProcessInfoLight(pb_allowlist->mutable_instigator(), msg->version, msg->process,
|
||||
enriched_process);
|
||||
EncodeProcessInfoLight(pb_allowlist->mutable_instigator(), msg->process, enriched_process);
|
||||
|
||||
EncodeFileInfo(pb_allowlist->mutable_target(), es_file, enriched_file,
|
||||
[NSString stringWithFormat:@"%s", hash.data()]);
|
||||
@@ -815,9 +1047,9 @@ static void EncodeDisk(::pbv1::Disk *pb_disk, ::pbv1::Disk_Action action, NSDict
|
||||
NSString *dmg_path = nil;
|
||||
NSString *serial = nil;
|
||||
if ([props[@"DADeviceModel"] isEqual:@"Disk Image"]) {
|
||||
dmg_path = Utilities::DiskImageForDevice(props[@"DADevicePath"]);
|
||||
dmg_path = santa::DiskImageForDevice(props[@"DADevicePath"]);
|
||||
} else {
|
||||
serial = Utilities::SerialForDevice(props[@"DADevicePath"]);
|
||||
serial = santa::SerialForDevice(props[@"DADevicePath"]);
|
||||
}
|
||||
|
||||
NSString *model = [NSString
|
||||
@@ -871,4 +1103,4 @@ std::vector<uint8_t> Protobuf::SerializeDiskDisappeared(NSDictionary *props) {
|
||||
return FinalizeProto(santa_msg);
|
||||
}
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <uuid/uuid.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "Source/common/Platform.h"
|
||||
#import "Source/common/SNTCachedDecision.h"
|
||||
#import "Source/common/SNTCommonEnums.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
@@ -49,16 +50,16 @@ using JsonPrintOptions = google::protobuf::json::PrintOptions;
|
||||
using JsonParseOptions = ::google::protobuf::json::ParseOptions;
|
||||
using google::protobuf::json::JsonStringToMessage;
|
||||
using google::protobuf::json::MessageToJsonString;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedEventType;
|
||||
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
|
||||
using santa::santad::event_providers::endpoint_security::Enricher;
|
||||
using santa::santad::event_providers::endpoint_security::Message;
|
||||
using santa::santad::logs::endpoint_security::serializers::Protobuf;
|
||||
using santa::santad::logs::endpoint_security::serializers::Serializer;
|
||||
using santa::EnrichedEventType;
|
||||
using santa::EnrichedMessage;
|
||||
using santa::Enricher;
|
||||
using santa::Message;
|
||||
using santa::Protobuf;
|
||||
using santa::Serializer;
|
||||
|
||||
namespace pbv1 = ::santa::pb::v1;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
extern void EncodeExitStatus(::pbv1::Exit *pbExit, int exitStatus);
|
||||
extern void EncodeEntitlements(::pbv1::Execution *pb_exec, SNTCachedDecision *cd);
|
||||
extern ::pbv1::Execution::Decision GetDecisionEnum(SNTEventState event_state);
|
||||
@@ -67,16 +68,24 @@ extern ::pbv1::Execution::Mode GetModeEnum(SNTClientMode mode);
|
||||
extern ::pbv1::FileDescriptor::FDType GetFileDescriptorType(uint32_t fdtype);
|
||||
extern ::pbv1::FileAccess::AccessType GetAccessType(es_event_type_t event_type);
|
||||
extern ::pbv1::FileAccess::PolicyDecision GetPolicyDecision(FileAccessPolicyDecision decision);
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
#if HAVE_MACOS_13
|
||||
extern ::pbv1::SocketAddress::Type GetSocketAddressType(es_address_type_t type);
|
||||
extern ::pbv1::OpenSSHLogin::Result GetOpenSSHLoginResultType(es_openssh_login_result_type_t type);
|
||||
#endif // HAVE_MACOS_13
|
||||
} // namespace santa
|
||||
|
||||
using santa::santad::logs::endpoint_security::serializers::EncodeEntitlements;
|
||||
using santa::santad::logs::endpoint_security::serializers::EncodeExitStatus;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetAccessType;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetDecisionEnum;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetFileDescriptorType;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetModeEnum;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetPolicyDecision;
|
||||
using santa::santad::logs::endpoint_security::serializers::GetReasonEnum;
|
||||
using santa::EncodeEntitlements;
|
||||
using santa::EncodeExitStatus;
|
||||
using santa::GetAccessType;
|
||||
using santa::GetDecisionEnum;
|
||||
using santa::GetFileDescriptorType;
|
||||
using santa::GetModeEnum;
|
||||
using santa::GetPolicyDecision;
|
||||
using santa::GetReasonEnum;
|
||||
#if HAVE_MACOS_13
|
||||
using santa::GetOpenSSHLoginResultType;
|
||||
using santa::GetSocketAddressType;
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
@interface ProtobufTest : XCTestCase
|
||||
@property id mockConfigurator;
|
||||
@@ -93,34 +102,51 @@ JsonPrintOptions DefaultJsonPrintOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
NSString *EventTypeToFilename(es_event_type_t eventType) {
|
||||
NSString *ConstructFilename(es_event_type_t eventType, NSString *variant = nil) {
|
||||
NSString *name;
|
||||
switch (eventType) {
|
||||
case ES_EVENT_TYPE_NOTIFY_CLOSE: return @"close.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA: return @"exchangedata.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC: return @"exec.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_EXIT: return @"exit.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_FORK: return @"fork.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_LINK: return @"link.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME: return @"rename.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_UNLINK: return @"unlink.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED: return @"cs_invalidated.json";
|
||||
case ES_EVENT_TYPE_NOTIFY_CLOSE: name = @"close"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA: name = @"exchangedata"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC: name = @"exec"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_EXIT: name = @"exit"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_FORK: name = @"fork"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LINK: name = @"link"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME: name = @"rename"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_UNLINK: name = @"unlink"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED: name = @"cs_invalidated"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN: name = @"lw_session_login"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT: name = @"lw_session_logout"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK: name = @"lw_session_lock"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK: name = @"lw_session_unlock"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH: name = @"screensharing_attach"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH: name = @"screensharing_detach"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN: name = @"openssh_login"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT: name = @"openssh_logout"; break;
|
||||
case ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN: name = @"login_login"; break;
|
||||
default: XCTFail(@"Unhandled event type: %d", eventType); return nil;
|
||||
}
|
||||
|
||||
if (variant) {
|
||||
return [NSString stringWithFormat:@"%@_%@.json", name, variant];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"%@.json", name];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *TestJsonPath(NSString *jsonFileName, uint32_t version) {
|
||||
NSString *p = [NSString pathWithComponents:@[
|
||||
NSString *LoadTestJson(NSString *jsonFileName, uint32_t version) {
|
||||
if (!jsonFileName) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *path = [NSString pathWithComponents:@[
|
||||
[[NSBundle bundleForClass:[ProtobufTest class]] resourcePath],
|
||||
@"protobuf",
|
||||
[NSString stringWithFormat:@"v%u", version],
|
||||
jsonFileName,
|
||||
]];
|
||||
return p;
|
||||
}
|
||||
|
||||
NSString *LoadTestJson(NSString *jsonFileName, uint32_t version) {
|
||||
NSError *err = nil;
|
||||
NSString *jsonData = [NSString stringWithContentsOfFile:TestJsonPath(jsonFileName, version)
|
||||
NSString *jsonData = [NSString stringWithContentsOfFile:path
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:&err];
|
||||
|
||||
@@ -150,6 +176,10 @@ const google::protobuf::Message &SantaMessageEvent(const ::pbv1::SantaMessage &s
|
||||
case ::pbv1::SantaMessage::kAllowlist: return santaMsg.allowlist();
|
||||
case ::pbv1::SantaMessage::kFileAccess: return santaMsg.file_access();
|
||||
case ::pbv1::SantaMessage::kCodesigningInvalidated: return santaMsg.codesigning_invalidated();
|
||||
case ::pbv1::SantaMessage::kLoginWindowSession: return santaMsg.login_window_session();
|
||||
case ::pbv1::SantaMessage::kScreenSharing: return santaMsg.screen_sharing();
|
||||
case ::pbv1::SantaMessage::kOpenSsh: return santaMsg.open_ssh();
|
||||
case ::pbv1::SantaMessage::kLoginLogout: return santaMsg.login_logout();
|
||||
case ::pbv1::SantaMessage::EVENT_NOT_SET:
|
||||
XCTFail(@"Protobuf message SantaMessage did not set an 'event' field");
|
||||
OS_FALLTHROUGH;
|
||||
@@ -203,11 +233,11 @@ NSDictionary *FindDelta(NSDictionary *want, NSDictionary *got) {
|
||||
void SerializeAndCheck(es_event_type_t eventType,
|
||||
void (^messageSetup)(std::shared_ptr<MockEndpointSecurityAPI>,
|
||||
es_message_t *),
|
||||
SNTDecisionCache *decisionCache, bool json = false) {
|
||||
SNTDecisionCache *decisionCache, bool json, NSString *variant) {
|
||||
std::shared_ptr<MockEndpointSecurityAPI> mockESApi = std::make_shared<MockEndpointSecurityAPI>();
|
||||
|
||||
for (uint32_t cur_version = 1; cur_version <= MaxSupportedESMessageVersionForCurrentOS();
|
||||
cur_version++) {
|
||||
for (uint32_t cur_version = MinSupportedESMessageVersion(eventType);
|
||||
cur_version <= MaxSupportedESMessageVersionForCurrentOS(); cur_version++) {
|
||||
if (cur_version == 3) {
|
||||
// Note: Version 3 was only in a macOS beta.
|
||||
continue;
|
||||
@@ -231,26 +261,23 @@ void SerializeAndCheck(es_event_type_t eventType,
|
||||
struct timespec enrichmentTime;
|
||||
struct timespec msgTime;
|
||||
NSString *wantData = std::visit(
|
||||
[&msgTime, &enrichmentTime](const EnrichedEventType &enrichedEvent) {
|
||||
msgTime = enrichedEvent.es_msg().time;
|
||||
[&msgTime, &enrichmentTime, variant](const EnrichedEventType &enrichedEvent) {
|
||||
msgTime = enrichedEvent->time;
|
||||
enrichmentTime = enrichedEvent.enrichment_time();
|
||||
|
||||
return LoadTestJson(EventTypeToFilename(enrichedEvent.es_msg().event_type),
|
||||
enrichedEvent.es_msg().version);
|
||||
return LoadTestJson(ConstructFilename(enrichedEvent->event_type, variant),
|
||||
enrichedEvent->version);
|
||||
},
|
||||
enrichedMsg->GetEnrichedMessage());
|
||||
|
||||
std::vector<uint8_t> vec = bs->SerializeMessage(std::move(enrichedMsg));
|
||||
std::string protoStr(vec.begin(), vec.end());
|
||||
|
||||
// if we're checking against JSON then we should already have a jsonified string and just need
|
||||
// to
|
||||
::pbv1::SantaMessage santaMsg;
|
||||
std::string gotData;
|
||||
|
||||
if (json) {
|
||||
// Parse the jsonified string into the protobuf
|
||||
// gotData = protoStr;
|
||||
JsonParseOptions options;
|
||||
options.ignore_unknown_fields = true;
|
||||
absl::Status status = JsonStringToMessage(protoStr, &santaMsg, options);
|
||||
@@ -287,7 +314,7 @@ void SerializeAndCheck(es_event_type_t eventType,
|
||||
}
|
||||
|
||||
void SerializeAndCheckNonESEvents(
|
||||
es_event_type_t eventType, NSString *filename,
|
||||
uint32_t minAssociatedESVersion, es_event_type_t eventType, NSString *filename,
|
||||
void (^messageSetup)(std::shared_ptr<MockEndpointSecurityAPI>, es_message_t *),
|
||||
std::vector<uint8_t> (^RunSerializer)(std::shared_ptr<Serializer> serializer,
|
||||
const Message &msg)) {
|
||||
@@ -295,8 +322,8 @@ void SerializeAndCheckNonESEvents(
|
||||
mockESApi->SetExpectationsRetainReleaseMessage();
|
||||
std::shared_ptr<Serializer> bs = Protobuf::Create(mockESApi, nil);
|
||||
|
||||
for (uint32_t cur_version = 1; cur_version <= MaxSupportedESMessageVersionForCurrentOS();
|
||||
cur_version++) {
|
||||
for (uint32_t cur_version = minAssociatedESVersion;
|
||||
cur_version <= MaxSupportedESMessageVersionForCurrentOS(); cur_version++) {
|
||||
if (cur_version == 3) {
|
||||
// Note: Version 3 was only in a macOS beta.
|
||||
continue;
|
||||
@@ -375,7 +402,20 @@ void SerializeAndCheckNonESEvents(
|
||||
messageSetup:(void (^)(std::shared_ptr<MockEndpointSecurityAPI>,
|
||||
es_message_t *))messageSetup
|
||||
json:(BOOL)json {
|
||||
SerializeAndCheck(eventType, messageSetup, self.mockDecisionCache, (bool)json);
|
||||
SerializeAndCheck(eventType, messageSetup, self.mockDecisionCache, (bool)json, nil);
|
||||
}
|
||||
|
||||
- (void)serializeAndCheckEvent:(es_event_type_t)eventType
|
||||
messageSetup:(void (^)(std::shared_ptr<MockEndpointSecurityAPI>,
|
||||
es_message_t *))messageSetup {
|
||||
SerializeAndCheck(eventType, messageSetup, self.mockDecisionCache, false, nil);
|
||||
}
|
||||
|
||||
- (void)serializeAndCheckEvent:(es_event_type_t)eventType
|
||||
messageSetup:(void (^)(std::shared_ptr<MockEndpointSecurityAPI>,
|
||||
es_message_t *))messageSetup
|
||||
variant:(NSString *)variant {
|
||||
SerializeAndCheck(eventType, messageSetup, self.mockDecisionCache, false, variant);
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageClose {
|
||||
@@ -386,8 +426,7 @@ void SerializeAndCheckNonESEvents(
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.close.modified = true;
|
||||
esMsg->event.close.target = &file;
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageExchange {
|
||||
@@ -399,8 +438,7 @@ void SerializeAndCheckNonESEvents(
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.exchangedata.file1 = &file1;
|
||||
esMsg->event.exchangedata.file2 = &file2;
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testGetDecisionEnum {
|
||||
@@ -539,8 +577,7 @@ void SerializeAndCheckNonESEvents(
|
||||
.WillOnce(testing::Return(&fd2))
|
||||
.WillOnce(testing::Return(&fd3));
|
||||
}
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageExecJSON {
|
||||
@@ -664,8 +701,7 @@ void SerializeAndCheckNonESEvents(
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.exit.stat = W_EXITCODE(1, 0);
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testEncodeExitStatus {
|
||||
@@ -702,8 +738,7 @@ void SerializeAndCheckNonESEvents(
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.fork.child = &procChild;
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLink {
|
||||
@@ -717,8 +752,7 @@ void SerializeAndCheckNonESEvents(
|
||||
esMsg->event.link.source = &fileSource;
|
||||
esMsg->event.link.target_dir = &fileTargetDir;
|
||||
esMsg->event.link.target_filename = targetTok;
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageRename {
|
||||
@@ -739,8 +773,7 @@ void SerializeAndCheckNonESEvents(
|
||||
esMsg->event.rename.destination.new_path.filename = targetTok;
|
||||
esMsg->event.rename.destination_type = ES_DESTINATION_TYPE_NEW_PATH;
|
||||
}
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageUnlink {
|
||||
@@ -752,8 +785,7 @@ void SerializeAndCheckNonESEvents(
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.unlink.target = &fileTarget;
|
||||
esMsg->event.unlink.parent_dir = &fileTargetParent;
|
||||
}
|
||||
json:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageCodesigningInvalidated {
|
||||
@@ -764,6 +796,219 @@ void SerializeAndCheckNonESEvents(
|
||||
json:NO];
|
||||
}
|
||||
|
||||
#if HAVE_MACOS_13
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLogin {
|
||||
__block es_event_lw_session_login_t lwLogin = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.lw_session_login = &lwLogin;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLogout {
|
||||
__block es_event_lw_session_logout_t lwLogout = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.lw_session_logout = &lwLogout;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionLock {
|
||||
__block es_event_lw_session_lock_t lwLock = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.lw_session_lock = &lwLock;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginWindowSessionUnlock {
|
||||
__block es_event_lw_session_unlock_t lwUnlock = {
|
||||
.username = MakeESStringToken("daemon"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.lw_session_unlock = &lwUnlock;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageScreensharingAttach {
|
||||
__block es_event_screensharing_attach_t attach = {
|
||||
.success = true,
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV6,
|
||||
.source_address = MakeESStringToken("::1"),
|
||||
.viewer_appleid = MakeESStringToken("foo@example.com"),
|
||||
.authentication_type = MakeESStringToken("idk"),
|
||||
.authentication_username = MakeESStringToken("my_auth_user"),
|
||||
.session_username = MakeESStringToken("my_session_user"),
|
||||
.existing_session = true,
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.screensharing_attach = &attach;
|
||||
}];
|
||||
|
||||
attach.source_address_type = (es_address_type_t)1234;
|
||||
attach.source_address = MakeESStringToken(NULL);
|
||||
attach.viewer_appleid = MakeESStringToken(NULL);
|
||||
attach.authentication_type = MakeESStringToken(NULL);
|
||||
attach.authentication_username = MakeESStringToken(NULL);
|
||||
attach.session_username = MakeESStringToken(NULL);
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.screensharing_attach = &attach;
|
||||
}
|
||||
variant:@"unset_fields"];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageScreensharingDetach {
|
||||
__block es_event_screensharing_detach_t detach = {
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV4,
|
||||
.source_address = MakeESStringToken("1.2.3.4"),
|
||||
.viewer_appleid = MakeESStringToken("foo@example.com"),
|
||||
.graphical_session_id = 123,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.screensharing_detach = &detach;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageOpenSSHLogin {
|
||||
__block es_event_openssh_login_t sshLogin = {.success = true,
|
||||
.result_type = ES_OPENSSH_AUTH_SUCCESS,
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV4,
|
||||
.source_address = MakeESStringToken("1.2.3.4"),
|
||||
.username = MakeESStringToken("foo_user"),
|
||||
.has_uid = true,
|
||||
.uid = {
|
||||
.uid = 12345,
|
||||
}};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.openssh_login = &sshLogin;
|
||||
}];
|
||||
|
||||
sshLogin.success = false;
|
||||
sshLogin.result_type = ES_OPENSSH_AUTH_FAIL_HOSTBASED;
|
||||
sshLogin.source_address_type = ES_ADDRESS_TYPE_IPV6;
|
||||
sshLogin.source_address = MakeESStringToken("::1");
|
||||
sshLogin.has_uid = false;
|
||||
sshLogin.username = MakeESStringToken(NULL);
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.openssh_login = &sshLogin;
|
||||
}
|
||||
variant:@"failed_attempt"];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageOpenSSHLogout {
|
||||
__block es_event_openssh_logout_t sshLogout = {
|
||||
.source_address_type = ES_ADDRESS_TYPE_IPV4,
|
||||
.source_address = MakeESStringToken("1.2.3.4"),
|
||||
.username = MakeESStringToken("foo_user"),
|
||||
.uid = 12345,
|
||||
};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.openssh_logout = &sshLogout;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testSerializeMessageLoginLogin {
|
||||
__block es_event_login_login_t login = {.success = true,
|
||||
.failure_message = MakeESStringToken(NULL),
|
||||
.username = MakeESStringToken("asdf"),
|
||||
.has_uid = true,
|
||||
.uid = {
|
||||
.uid = 321,
|
||||
}};
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.login_login = &login;
|
||||
}];
|
||||
|
||||
login.success = false;
|
||||
login.failure_message = MakeESStringToken("my|failure");
|
||||
login.has_uid = false;
|
||||
|
||||
[self serializeAndCheckEvent:ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN
|
||||
messageSetup:^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi,
|
||||
es_message_t *esMsg) {
|
||||
esMsg->event.login_login = &login;
|
||||
}
|
||||
variant:@"failed_attempt"];
|
||||
}
|
||||
|
||||
- (void)testGetSocketAddressType {
|
||||
std::map<es_address_type_t, ::pbv1::SocketAddress::Type> esToSantaAddrType = {
|
||||
{ES_ADDRESS_TYPE_NONE, ::pbv1::SocketAddress::TYPE_NONE},
|
||||
{ES_ADDRESS_TYPE_IPV4, ::pbv1::SocketAddress::TYPE_IPV4},
|
||||
{ES_ADDRESS_TYPE_IPV6, ::pbv1::SocketAddress::TYPE_IPV6},
|
||||
{ES_ADDRESS_TYPE_NAMED_SOCKET, ::pbv1::SocketAddress::TYPE_NAMED_SOCKET},
|
||||
{(es_address_type_t)1234, ::pbv1::SocketAddress::TYPE_UNKNOWN},
|
||||
};
|
||||
|
||||
for (const auto &kv : esToSantaAddrType) {
|
||||
XCTAssertEqual(GetSocketAddressType(kv.first), kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testGetOpenSSHLoginResultType {
|
||||
std::map<es_openssh_login_result_type_t, ::pbv1::OpenSSHLogin::Result> esToSantaOpenSSHResultType{
|
||||
{ES_OPENSSH_LOGIN_EXCEED_MAXTRIES, ::pbv1::OpenSSHLogin::RESULT_LOGIN_EXCEED_MAXTRIES},
|
||||
{ES_OPENSSH_LOGIN_ROOT_DENIED, ::pbv1::OpenSSHLogin::RESULT_LOGIN_ROOT_DENIED},
|
||||
{ES_OPENSSH_AUTH_SUCCESS, ::pbv1::OpenSSHLogin::RESULT_AUTH_SUCCESS},
|
||||
{ES_OPENSSH_AUTH_FAIL_NONE, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_NONE},
|
||||
{ES_OPENSSH_AUTH_FAIL_PASSWD, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_PASSWD},
|
||||
{ES_OPENSSH_AUTH_FAIL_KBDINT, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_KBDINT},
|
||||
{ES_OPENSSH_AUTH_FAIL_PUBKEY, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_PUBKEY},
|
||||
{ES_OPENSSH_AUTH_FAIL_HOSTBASED, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_HOSTBASED},
|
||||
{ES_OPENSSH_AUTH_FAIL_GSSAPI, ::pbv1::OpenSSHLogin::RESULT_AUTH_FAIL_GSSAPI},
|
||||
{ES_OPENSSH_INVALID_USER, ::pbv1::OpenSSHLogin::RESULT_INVALID_USER},
|
||||
{(es_openssh_login_result_type_t)1234, ::pbv1::OpenSSHLogin::RESULT_UNKNOWN},
|
||||
};
|
||||
|
||||
for (const auto &kv : esToSantaOpenSSHResultType) {
|
||||
XCTAssertEqual(GetOpenSSHLoginResultType(kv.first), kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_MACOS_13
|
||||
|
||||
- (void)testGetAccessType {
|
||||
std::map<es_event_type_t, ::pbv1::FileAccess::AccessType> eventTypeToAccessType = {
|
||||
{ES_EVENT_TYPE_AUTH_CLONE, ::pbv1::FileAccess::ACCESS_TYPE_CLONE},
|
||||
@@ -805,7 +1050,7 @@ void SerializeAndCheckNonESEvents(
|
||||
- (void)testSerializeFileAccess {
|
||||
__block es_file_t openFile = MakeESFile("open_file", MakeStat(300));
|
||||
SerializeAndCheckNonESEvents(
|
||||
ES_EVENT_TYPE_AUTH_OPEN, @"file_access.json",
|
||||
6, ES_EVENT_TYPE_AUTH_OPEN, @"file_access.json",
|
||||
^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi, es_message_t *esMsg) {
|
||||
esMsg->event.open.file = &openFile;
|
||||
},
|
||||
@@ -819,7 +1064,7 @@ void SerializeAndCheckNonESEvents(
|
||||
- (void)testSerializeAllowlist {
|
||||
__block es_file_t closeFile = MakeESFile("close_file", MakeStat(300));
|
||||
SerializeAndCheckNonESEvents(
|
||||
ES_EVENT_TYPE_NOTIFY_CLOSE, @"allowlist.json",
|
||||
1, ES_EVENT_TYPE_NOTIFY_CLOSE, @"allowlist.json",
|
||||
^(std::shared_ptr<MockEndpointSecurityAPI> mockESApi, es_message_t *esMsg) {
|
||||
esMsg->event.close.target = &closeFile;
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
// Small helper class that will sanitize a given string, but will only use new
|
||||
// memory if the string required sanitization. If the string is already
|
||||
@@ -56,6 +56,6 @@ class SanitizableString {
|
||||
mutable std::optional<std::string> sanitized_string_;
|
||||
};
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
#include "Source/common/String.h"
|
||||
|
||||
using santa::common::NSStringToUTF8StringView;
|
||||
using santa::NSStringToUTF8StringView;
|
||||
|
||||
namespace santa::santad::logs::endpoint_security::serializers {
|
||||
namespace santa {
|
||||
|
||||
SanitizableString::SanitizableString(const es_file_t *file)
|
||||
: data_(file->path.data, file->path.length) {}
|
||||
@@ -108,4 +108,4 @@ std::optional<std::string> SanitizableString::SanitizeString(const char *str, si
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace santa::santad::logs::endpoint_security::serializers
|
||||
} // namespace santa
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "Source/common/TestUtils.h"
|
||||
|
||||
using santa::santad::logs::endpoint_security::serializers::SanitizableString;
|
||||
using santa::SanitizableString;
|
||||
|
||||
@interface SanitizableStringTest : XCTestCase
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user