Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd23a5c3b7 | ||
|
|
ec203e8796 | ||
|
|
57ff69208d | ||
|
|
f00b7d2ded | ||
|
|
9791fdd53c | ||
|
|
26e2203f1e | ||
|
|
4a47195d12 | ||
|
|
4436e221df | ||
|
|
deccc8a148 | ||
|
|
06da796a4d | ||
|
|
7b99a76d0d | ||
|
|
c2d3e99446 | ||
|
|
6db7fea8ae | ||
|
|
6fcb4cfe63 | ||
|
|
8b55ee4da5 |
@@ -1,13 +1,14 @@
|
||||
name: Check Markdown links
|
||||
name: Check Markdown
|
||||
|
||||
on:
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
markdown-link-check:
|
||||
markdown-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: gaurav-nelson/github-action-markdown-link-check@v1
|
||||
- run: "! git grep -EIn $'[ \t]+$'"
|
||||
1
.github/workflows/ci.yml
vendored
@@ -20,6 +20,7 @@ jobs:
|
||||
- name: Run linters
|
||||
run: ./Testing/lint.sh
|
||||
|
||||
|
||||
build_userspace:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
7
BUILD
@@ -74,14 +74,14 @@ launchctl load /Library/LaunchAgents/com.google.santa.plist
|
||||
run_command(
|
||||
name = "reload",
|
||||
srcs = [
|
||||
"//Source/santa:Santa",
|
||||
"//Source/gui:Santa",
|
||||
],
|
||||
cmd = """
|
||||
set -e
|
||||
|
||||
rm -rf /tmp/bazel_santa_reload
|
||||
unzip -d /tmp/bazel_santa_reload \
|
||||
$${BUILD_WORKSPACE_DIRECTORY}/bazel-out/*$(COMPILATION_MODE)*/bin/Source/santa/Santa.zip >/dev/null
|
||||
$${BUILD_WORKSPACE_DIRECTORY}/bazel-out/*$(COMPILATION_MODE)*/bin/Source/gui/Santa.zip >/dev/null
|
||||
echo "You may be asked for your password for sudo"
|
||||
sudo BINARIES=/tmp/bazel_santa_reload CONF=$${BUILD_WORKSPACE_DIRECTORY}/Conf \
|
||||
$${BUILD_WORKSPACE_DIRECTORY}/Conf/install.sh
|
||||
@@ -96,7 +96,7 @@ echo "Time to stop being naughty"
|
||||
genrule(
|
||||
name = "release",
|
||||
srcs = [
|
||||
"//Source/santa:Santa",
|
||||
"//Source/gui:Santa",
|
||||
"Conf/install.sh",
|
||||
"Conf/uninstall.sh",
|
||||
"Conf/com.google.santa.bundleservice.plist",
|
||||
@@ -191,6 +191,7 @@ test_suite(
|
||||
name = "unit_tests",
|
||||
tests = [
|
||||
"//Source/common:unit_tests",
|
||||
"//Source/gui:unit_tests",
|
||||
"//Source/santactl:unit_tests",
|
||||
"//Source/santad:unit_tests",
|
||||
"//Source/santametricservice:unit_tests",
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<img src="https://raw.githubusercontent.com/google/santa/main/Source/santa/Resources/Images.xcassets/AppIcon.appiconset/santa-hat-icon-128.png" alt="Santa Icon" />
|
||||
</p>
|
||||
|
||||
Santa is a binary authorization system for macOS. It consists of a system
|
||||
extension that monitors for executions, a daemon that makes execution decisions
|
||||
Santa is a binary authorization system for macOS. It consists of a system
|
||||
extension that monitors for executions, a daemon that makes execution decisions
|
||||
based on the contents of a local database, a GUI agent that notifies the user in
|
||||
case of a block decision and a command-line utility for managing the system and
|
||||
case of a block decision and a command-line utility for managing the system and
|
||||
synchronizing the database with a server.
|
||||
|
||||
It is named Santa because it keeps track of binaries that are naughty or nice.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Reporting a Vulnerability
|
||||
|
||||
If you believe you have found a security vulnerability, we would appreciate private disclosure
|
||||
so that we can work on a fix before disclosure. Any vulnerabilities reported to us will be
|
||||
so that we can work on a fix before disclosure. Any vulnerabilities reported to us will be
|
||||
disclosed publicly either when a new version with fixes is released or 90 days has passed,
|
||||
whichever comes first.
|
||||
|
||||
|
||||
@@ -255,6 +255,16 @@
|
||||
|
||||
#pragma mark - GUI Settings
|
||||
|
||||
///
|
||||
/// When silent mode is enabled, Santa will never show notifications for
|
||||
/// blocked processes.
|
||||
///
|
||||
/// This can be a very confusing experience for users, use with caution.
|
||||
///
|
||||
/// Defaults to NO.
|
||||
///
|
||||
@property(readonly, nonatomic) BOOL enableSilentMode;
|
||||
|
||||
///
|
||||
/// The text to display when opening Santa.app.
|
||||
/// If unset, the default text will be displayed.
|
||||
|
||||
@@ -66,7 +66,8 @@ static NSString *const kMachineOwnerPlistKeyKey = @"MachineOwnerKey";
|
||||
static NSString *const kMachineIDPlistFileKey = @"MachineIDPlist";
|
||||
static NSString *const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
|
||||
static NSString *const kAboutText = @"AboutText";
|
||||
static NSString *const kEnableSilentModeKey = @"EnableSilentMode";
|
||||
static NSString *const kAboutTextKey = @"AboutText";
|
||||
static NSString *const kMoreInfoURLKey = @"MoreInfoURL";
|
||||
static NSString *const kEventDetailURLKey = @"EventDetailURL";
|
||||
static NSString *const kEventDetailTextKey = @"EventDetailText";
|
||||
@@ -172,7 +173,8 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
kRemountUSBModeKey : array,
|
||||
kEnablePageZeroProtectionKey : number,
|
||||
kEnableBadSignatureProtectionKey : number,
|
||||
kAboutText : string,
|
||||
kEnableSilentModeKey : string,
|
||||
kAboutTextKey : string,
|
||||
kMoreInfoURLKey : string,
|
||||
kEventDetailURLKey : string,
|
||||
kEventDetailTextKey : string,
|
||||
@@ -303,6 +305,10 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEnableSilentMode {
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingAboutText {
|
||||
return [self configStateSet];
|
||||
}
|
||||
@@ -611,8 +617,13 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
return number ? [number boolValue] : NO;
|
||||
}
|
||||
|
||||
- (BOOL)enableSilentMode {
|
||||
NSNumber *number = self.configState[kEnableSilentModeKey];
|
||||
return number ? [number boolValue] : NO;
|
||||
}
|
||||
|
||||
- (NSString *)aboutText {
|
||||
return self.configState[kAboutText];
|
||||
return self.configState[kAboutTextKey];
|
||||
}
|
||||
|
||||
- (NSURL *)moreInfoURL {
|
||||
@@ -959,7 +970,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
syncState[kAllowedPathRegexKey] = [syncState[kAllowedPathRegexKey] pattern];
|
||||
syncState[kBlockedPathRegexKey] = [syncState[kBlockedPathRegexKey] pattern];
|
||||
[syncState writeToFile:kSyncStateFilePath atomically:YES];
|
||||
[[NSFileManager defaultManager] setAttributes:@{NSFilePosixPermissions : @0644}
|
||||
[[NSFileManager defaultManager] setAttributes:@{NSFilePosixPermissions : @0600}
|
||||
ofItemAtPath:kSyncStateFilePath
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_application")
|
||||
load("//:helper.bzl", "santa_unit_test")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
@@ -31,6 +32,9 @@ objc_library(
|
||||
"SNTNotificationManager.m",
|
||||
"main.m",
|
||||
],
|
||||
hdrs = [
|
||||
"SNTNotificationManager.h",
|
||||
],
|
||||
data = [
|
||||
"Resources/AboutWindow.xib",
|
||||
"Resources/DeviceMessageWindow.xib",
|
||||
@@ -49,6 +53,7 @@ objc_library(
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTStoredEvent",
|
||||
"//Source/common:SNTStrengthify",
|
||||
"//Source/common:SNTSyncConstants",
|
||||
"//Source/common:SNTXPCControlInterface",
|
||||
"//Source/common:SNTXPCNotifierInterface",
|
||||
"@MOLCertificate",
|
||||
@@ -89,3 +94,26 @@ macos_application(
|
||||
visibility = ["//:santa_package_group"],
|
||||
deps = [":SantaGUI_lib"],
|
||||
)
|
||||
|
||||
santa_unit_test(
|
||||
name = "SNTNotificationManagerTest",
|
||||
srcs = [
|
||||
"SNTNotificationManagerTest.m",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"Cocoa",
|
||||
],
|
||||
deps = [
|
||||
":SantaGUI_lib",
|
||||
"//Source/common:SNTStoredEvent",
|
||||
"@OCMock",
|
||||
],
|
||||
)
|
||||
|
||||
test_suite(
|
||||
name = "unit_tests",
|
||||
tests = [
|
||||
":SNTNotificationManagerTest",
|
||||
],
|
||||
visibility = ["//:santa_package_group"],
|
||||
)
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTAboutWindowController.h"
|
||||
#import "Source/gui/SNTAboutWindowController.h"
|
||||
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTAccessibleTextField.h"
|
||||
#import "Source/gui/SNTAccessibleTextField.h"
|
||||
|
||||
@implementation SNTAccessibleTextField
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTAppDelegate.h"
|
||||
#import "Source/gui/SNTAppDelegate.h"
|
||||
|
||||
#import <MOLXPCConnection/MOLXPCConnection.h>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#import "Source/common/SNTLogging.h"
|
||||
#import "Source/common/SNTStrengthify.h"
|
||||
#import "Source/common/SNTXPCControlInterface.h"
|
||||
#import "Source/santa/SNTAboutWindowController.h"
|
||||
#import "Source/santa/SNTNotificationManager.h"
|
||||
#import "Source/gui/SNTAboutWindowController.h"
|
||||
#import "Source/gui/SNTNotificationManager.h"
|
||||
|
||||
@interface SNTAppDelegate ()
|
||||
@property SNTAboutWindowController *aboutWindowController;
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "Source/santa/SNTMessageWindowController.h"
|
||||
#import "Source/gui/SNTMessageWindowController.h"
|
||||
|
||||
@class SNTStoredEvent;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTBinaryMessageWindowController.h"
|
||||
#import "Source/gui/SNTBinaryMessageWindowController.h"
|
||||
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <SecurityInterface/SFCertificatePanel.h>
|
||||
@@ -20,7 +20,7 @@
|
||||
#import "Source/common/SNTBlockMessage.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
#import "Source/common/SNTStoredEvent.h"
|
||||
#import "Source/santa/SNTMessageWindow.h"
|
||||
#import "Source/gui/SNTMessageWindow.h"
|
||||
|
||||
@interface SNTBinaryMessageWindowController ()
|
||||
/// The custom message to display for this event
|
||||
@@ -139,7 +139,9 @@
|
||||
- (NSString *)publisherInfo {
|
||||
MOLCertificate *leafCert = [self.event.signingChain firstObject];
|
||||
|
||||
if (leafCert.commonName && leafCert.orgName) {
|
||||
if ([leafCert.commonName isEqualToString:@"Apple Mac OS Application Signing"]) {
|
||||
return [NSString stringWithFormat:@"App Store (Team ID: %@)", self.event.teamID];
|
||||
} else if (leafCert.commonName && leafCert.orgName) {
|
||||
return [NSString stringWithFormat:@"%@ - %@", leafCert.orgName, leafCert.commonName];
|
||||
} else if (leafCert.commonName) {
|
||||
return leafCert.commonName;
|
||||
@@ -14,7 +14,7 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "Source/common/SNTDeviceEvent.h"
|
||||
#import "Source/santa/SNTMessageWindowController.h"
|
||||
#import "Source/gui/SNTMessageWindowController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTDeviceMessageWindowController.h"
|
||||
#import "Source/gui/SNTDeviceMessageWindowController.h"
|
||||
|
||||
#import "Source/common/SNTBlockMessage.h"
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
#import "Source/common/SNTDeviceEvent.h"
|
||||
#import "Source/santa/SNTMessageWindow.h"
|
||||
#import "Source/gui/SNTMessageWindow.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTMessageWindow.h"
|
||||
#import "Source/gui/SNTMessageWindow.h"
|
||||
|
||||
@implementation SNTMessageWindow
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#import "Source/santa/SNTMessageWindowController.h"
|
||||
#import "Source/gui/SNTMessageWindowController.h"
|
||||
|
||||
#import "Source/santa/SNTMessageWindow.h"
|
||||
#import "Source/gui/SNTMessageWindow.h"
|
||||
|
||||
@implementation SNTMessageWindowController
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "Source/common/SNTXPCNotifierInterface.h"
|
||||
#import "Source/santa/SNTBinaryMessageWindowController.h"
|
||||
#import "Source/santa/SNTDeviceMessageWindowController.h"
|
||||
#import "Source/santa/SNTMessageWindowController.h"
|
||||
#import "Source/gui/SNTBinaryMessageWindowController.h"
|
||||
#import "Source/gui/SNTDeviceMessageWindowController.h"
|
||||
#import "Source/gui/SNTMessageWindowController.h"
|
||||
|
||||
///
|
||||
/// Keeps track of pending notifications and ensures only one is presented to the user at a time.
|
||||
@@ -12,8 +12,9 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santa/SNTNotificationManager.h"
|
||||
#import "Source/gui/SNTNotificationManager.h"
|
||||
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <MOLXPCConnection/MOLXPCConnection.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
@@ -23,8 +24,9 @@
|
||||
#import "Source/common/SNTLogging.h"
|
||||
#import "Source/common/SNTStoredEvent.h"
|
||||
#import "Source/common/SNTStrengthify.h"
|
||||
#import "Source/common/SNTSyncConstants.h"
|
||||
#import "Source/common/SNTXPCControlInterface.h"
|
||||
#import "Source/santa/SNTMessageWindowController.h"
|
||||
#import "Source/gui/SNTMessageWindowController.h"
|
||||
|
||||
@interface SNTNotificationManager ()
|
||||
|
||||
@@ -112,12 +114,59 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
|
||||
pendingMsg.delegate = self;
|
||||
[self.pendingNotifications addObject:pendingMsg];
|
||||
[self postDistributedNotification:pendingMsg];
|
||||
|
||||
if (!self.currentWindowController) {
|
||||
[self showQueuedWindow];
|
||||
}
|
||||
}
|
||||
|
||||
// For blocked execution notifications, post an NSDistributedNotificationCenter
|
||||
// notification with the important details from the stored event. Distributed
|
||||
// notifications are system-wide broadcasts that can be sent by apps and observed
|
||||
// from separate processes. This allows users of Santa to write tools that
|
||||
// perform actions when we block execution, such as trigger management tools or
|
||||
// display an enterprise-specific UI (which is particularly useful when combined
|
||||
// with the EnableSilentMode configuration option, to disable Santa's standard UI).
|
||||
- (void)postDistributedNotification:(SNTMessageWindowController *)pendingMsg {
|
||||
if (![pendingMsg isKindOfClass:[SNTBinaryMessageWindowController class]]) {
|
||||
return;
|
||||
}
|
||||
SNTBinaryMessageWindowController *wc = (SNTBinaryMessageWindowController *)pendingMsg;
|
||||
NSDistributedNotificationCenter *dc = [NSDistributedNotificationCenter defaultCenter];
|
||||
NSMutableArray<NSDictionary *> *signingChain =
|
||||
[NSMutableArray arrayWithCapacity:wc.event.signingChain.count];
|
||||
for (MOLCertificate *cert in wc.event.signingChain) {
|
||||
[signingChain addObject:@{
|
||||
kCertSHA256 : cert.SHA256 ?: @"",
|
||||
kCertCN : cert.commonName ?: @"",
|
||||
kCertOrg : cert.orgName ?: @"",
|
||||
kCertOU : cert.orgUnit ?: @"",
|
||||
kCertValidFrom : @([cert.validFrom timeIntervalSince1970]) ?: @0,
|
||||
kCertValidUntil : @([cert.validUntil timeIntervalSince1970]) ?: @0,
|
||||
}];
|
||||
}
|
||||
NSDictionary *userInfo = @{
|
||||
kFileSHA256 : wc.event.fileSHA256 ?: @"",
|
||||
kFilePath : wc.event.filePath ?: @"",
|
||||
kFileBundleName : wc.event.fileBundleName ?: @"",
|
||||
kFileBundleID : wc.event.fileBundleID ?: @"",
|
||||
kFileBundleVersion : wc.event.fileBundleVersion ?: @"",
|
||||
kFileBundleShortVersionString : wc.event.fileBundleVersionString ?: @"",
|
||||
kTeamID : wc.event.teamID ?: @"",
|
||||
kExecutingUser : wc.event.executingUser ?: @"",
|
||||
kExecutionTime : @([wc.event.occurrenceDate timeIntervalSince1970]) ?: @0,
|
||||
kPID : wc.event.pid ?: @0,
|
||||
kPPID : wc.event.ppid ?: @0,
|
||||
kParentName : wc.event.parentName ?: @"",
|
||||
kSigningChain : signingChain,
|
||||
};
|
||||
|
||||
[dc postNotificationName:@"com.google.santa.notification.blockedeexecution"
|
||||
object:@"com.google.santa"
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)showQueuedWindow {
|
||||
// Notifications arrive on a background thread but UI updates must happen on the main thread.
|
||||
// This includes making windows.
|
||||
@@ -208,6 +257,8 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
#pragma mark SNTNotifierXPC protocol methods
|
||||
|
||||
- (void)postClientModeNotification:(SNTClientMode)clientmode {
|
||||
if ([SNTConfigurator configurator].enableSilentMode) return;
|
||||
|
||||
UNUserNotificationCenter *un = [UNUserNotificationCenter currentNotificationCenter];
|
||||
|
||||
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
|
||||
@@ -246,6 +297,8 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
}
|
||||
|
||||
- (void)postRuleSyncNotificationWithCustomMessage:(NSString *)message {
|
||||
if ([SNTConfigurator configurator].enableSilentMode) return;
|
||||
|
||||
UNUserNotificationCenter *un = [UNUserNotificationCenter currentNotificationCenter];
|
||||
|
||||
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
|
||||
@@ -262,6 +315,8 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
}
|
||||
|
||||
- (void)postBlockNotification:(SNTStoredEvent *)event withCustomMessage:(NSString *)message {
|
||||
if ([SNTConfigurator configurator].enableSilentMode) return;
|
||||
|
||||
if (!event) {
|
||||
LOGI(@"Error: Missing event object in message received from daemon!");
|
||||
return;
|
||||
@@ -274,6 +329,8 @@ static NSString *const silencedNotificationsKey = @"SilencedNotifications";
|
||||
}
|
||||
|
||||
- (void)postUSBBlockNotification:(SNTDeviceEvent *)event withCustomMessage:(NSString *)message {
|
||||
if ([SNTConfigurator configurator].enableSilentMode) return;
|
||||
|
||||
if (!event) {
|
||||
LOGI(@"Error: Missing event object in message received from daemon!");
|
||||
return;
|
||||
76
Source/gui/SNTNotificationManagerTest.m
Normal file
@@ -0,0 +1,76 @@
|
||||
/// Copyright 2022 Google Inc. All rights reserved.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// http://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 <MOLCertificate/MOLCertificate.h>
|
||||
// #import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "Source/gui/SNTNotificationManager.h"
|
||||
|
||||
#import "Source/common/SNTStoredEvent.h"
|
||||
|
||||
@class SNTBinaryMessageWindowController;
|
||||
|
||||
@interface SNTNotificationManager (Testing)
|
||||
- (void)hashBundleBinariesForEvent:(SNTStoredEvent *)event
|
||||
withController:(SNTBinaryMessageWindowController *)controller;
|
||||
@end
|
||||
|
||||
@interface SNTNotificationManagerTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation SNTNotificationManagerTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
fclose(stdout);
|
||||
}
|
||||
|
||||
- (void)testPostBlockNotificationSendsDistributedNotification {
|
||||
SNTStoredEvent *ev = [[SNTStoredEvent alloc] init];
|
||||
ev.fileSHA256 = @"the-sha256";
|
||||
ev.filePath = @"/Applications/Safari.app/Contents/MacOS/Safari";
|
||||
ev.fileBundleName = @"Safari";
|
||||
ev.fileBundlePath = @"/Applications/Safari.app";
|
||||
ev.fileBundleID = @"com.apple.Safari";
|
||||
ev.fileBundleVersion = @"18614.1.14.1.15";
|
||||
ev.fileBundleVersionString = @"16.0";
|
||||
ev.executingUser = @"rah";
|
||||
ev.occurrenceDate = [NSDate dateWithTimeIntervalSince1970:1660221048];
|
||||
ev.decision = SNTEventStateBlockBinary;
|
||||
ev.pid = @84156;
|
||||
ev.ppid = @1;
|
||||
ev.parentName = @"launchd";
|
||||
|
||||
SNTNotificationManager *sut = OCMPartialMock([[SNTNotificationManager alloc] init]);
|
||||
OCMStub([sut hashBundleBinariesForEvent:OCMOCK_ANY withController:OCMOCK_ANY]).andDo(nil);
|
||||
|
||||
id dncMock = OCMClassMock([NSDistributedNotificationCenter class]);
|
||||
OCMStub([dncMock defaultCenter]).andReturn(dncMock);
|
||||
|
||||
[sut postBlockNotification:ev withCustomMessage:@""];
|
||||
|
||||
OCMVerify([dncMock postNotificationName:@"com.google.santa.notification.blockedeexecution"
|
||||
object:@"com.google.santa"
|
||||
userInfo:[OCMArg checkWithBlock:^BOOL(NSDictionary *userInfo) {
|
||||
XCTAssertEqualObjects(userInfo[@"file_sha256"], @"the-sha256");
|
||||
XCTAssertEqualObjects(userInfo[@"pid"], @84156);
|
||||
XCTAssertEqualObjects(userInfo[@"ppid"], @1);
|
||||
XCTAssertEqualObjects(userInfo[@"execution_time"], @1660221048);
|
||||
return YES;
|
||||
}]]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#import "Source/common/SNTConfigurator.h"
|
||||
#import "Source/common/SNTXPCControlInterface.h"
|
||||
#import "Source/santa/SNTAppDelegate.h"
|
||||
#import "Source/gui/SNTAppDelegate.h"
|
||||
|
||||
@interface SNTSystemExtensionDelegate : NSObject <OSSystemExtensionRequestDelegate>
|
||||
@end
|
||||
@@ -119,7 +119,7 @@ REGISTER_COMMAND_NAME(@"metrics")
|
||||
printf(">>> Root Labels\n");
|
||||
[self prettyPrintRootLabels:normalizedMetrics[@"root_labels"]];
|
||||
printf("\n");
|
||||
printf(">>> Metrics \n");
|
||||
printf(">>> Metrics\n");
|
||||
[self prettyPrintMetricValues:normalizedMetrics[@"metrics"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
hostname | testHost
|
||||
username | testUser
|
||||
|
||||
>>> Metrics
|
||||
>>> Metrics
|
||||
Metric Name | /santa/rules
|
||||
Description | Number of rules
|
||||
Type | SNTMetricTypeGaugeInt64
|
||||
|
||||
@@ -76,6 +76,7 @@ santa_unit_test(
|
||||
deps = [
|
||||
":SNTMetricFormatTestHelper",
|
||||
":SNTMetricMonarchJSONFormat",
|
||||
"@OCMock",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -100,7 +100,8 @@ const NSString *kKey = @"key";
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary *> *)encodeDataForMetric:(NSDictionary *)metric {
|
||||
- (NSArray<NSDictionary *> *)encodeDataForMetric:(NSDictionary *)metric
|
||||
withEndTimestamp:(NSDate *)endTimestamp {
|
||||
NSMutableArray<NSDictionary *> *monarchMetricData = [[NSMutableArray alloc] init];
|
||||
|
||||
for (NSString *fieldName in metric[@"fields"]) {
|
||||
@@ -112,8 +113,8 @@ const NSString *kKey = @"key";
|
||||
}
|
||||
|
||||
monarchDataEntry[kStartTimestamp] = [self->_dateFormatter stringFromDate:entry[@"created"]];
|
||||
monarchDataEntry[kEndTimestamp] =
|
||||
[self->_dateFormatter stringFromDate:entry[@"last_updated"]];
|
||||
// Monarch wants all the end timestamp to be updated, even if the value does not change.
|
||||
monarchDataEntry[kEndTimestamp] = [self->_dateFormatter stringFromDate:endTimestamp];
|
||||
|
||||
if (!metric[@"type"]) {
|
||||
LOGE(@"metric type is nil");
|
||||
@@ -157,10 +158,13 @@ const NSString *kKey = @"key";
|
||||
}
|
||||
|
||||
/**
|
||||
* formatMetric translates the SNTMetricSet metric entries into those consumable by Monarch.
|
||||
* formatMetric translates the SNTMetricSet metric entries into those consumable
|
||||
* by Monarch.
|
||||
**/
|
||||
|
||||
- (NSDictionary *)formatMetric:(NSString *)name withMetric:(NSDictionary *)metric {
|
||||
- (NSDictionary *)formatMetric:(NSString *)name
|
||||
withValue:(NSDictionary *)metric
|
||||
andEndtimestamp:(NSDate *)endTimestamp {
|
||||
NSMutableDictionary *monarchMetric = [[NSMutableDictionary alloc] init];
|
||||
|
||||
monarchMetric[kMetricName] = name;
|
||||
@@ -175,7 +179,7 @@ const NSString *kKey = @"key";
|
||||
}
|
||||
|
||||
[self encodeValueAndStreamKindFor:name withMetric:metric into:monarchMetric];
|
||||
monarchMetric[@"data"] = [self encodeDataForMetric:metric];
|
||||
monarchMetric[@"data"] = [self encodeDataForMetric:metric withEndTimestamp:endTimestamp];
|
||||
|
||||
return monarchMetric;
|
||||
}
|
||||
@@ -185,10 +189,12 @@ const NSString *kKey = @"key";
|
||||
**/
|
||||
- (NSDictionary *)normalize:(NSDictionary *)metrics {
|
||||
NSMutableArray<NSDictionary *> *monarchMetrics = [[NSMutableArray alloc] init];
|
||||
NSDate *endTimestamp = [NSDate date];
|
||||
|
||||
for (NSString *metricName in metrics[@"metrics"]) {
|
||||
[monarchMetrics addObject:[self formatMetric:metricName
|
||||
withMetric:metrics[@"metrics"][metricName]]];
|
||||
withValue:metrics[@"metrics"][metricName]
|
||||
andEndtimestamp:endTimestamp]];
|
||||
}
|
||||
|
||||
NSMutableArray<NSDictionary *> *rootLabels = [[NSMutableArray alloc] init];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import "Source/santametricservice/Formats/SNTMetricFormatTestHelper.h"
|
||||
#import "Source/santametricservice/Formats/SNTMetricMonarchJSONFormat.h"
|
||||
|
||||
@@ -9,6 +11,10 @@
|
||||
@implementation SNTMetricMonarchJSONFormatTest
|
||||
|
||||
- (void)testMetricsConversionToJSON {
|
||||
id classMock = OCMClassMock([NSDate class]);
|
||||
OCMStub([classMock date])
|
||||
.andReturn([NSDate dateWithTimeIntervalSince1970:1631826490]); // 2021-09-16 21:08:10Z
|
||||
|
||||
NSDictionary *validMetricsDict = [SNTMetricFormatTestHelper createValidMetricsDictionary];
|
||||
SNTMetricMonarchJSONFormat *formatter = [[SNTMetricMonarchJSONFormat alloc] init];
|
||||
NSError *err = nil;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"int64Value" : 1,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"field" : [
|
||||
{
|
||||
"name" : "rule_type",
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
{
|
||||
"int64Value" : 3,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"field" : [
|
||||
{
|
||||
"name" : "rule_type",
|
||||
@@ -54,7 +54,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"int64Value" : 123456789,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"startTimestamp" : "2021-09-16T21:07:34.826Z"
|
||||
}
|
||||
],
|
||||
@@ -73,7 +73,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"int64Value" : 1,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"field" : [
|
||||
{
|
||||
"name" : "rule_type",
|
||||
@@ -84,7 +84,7 @@
|
||||
},
|
||||
{
|
||||
"int64Value" : 2,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"field" : [
|
||||
{
|
||||
"name" : "rule_type",
|
||||
@@ -104,7 +104,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"boolValue" : true,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"startTimestamp" : "2021-09-16T21:07:34.826Z"
|
||||
}
|
||||
]
|
||||
@@ -116,7 +116,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"int64Value" : 1250999830800,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"startTimestamp" : "2021-09-16T21:07:34.826Z"
|
||||
}
|
||||
]
|
||||
@@ -127,7 +127,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"int64Value" : 987654321,
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"startTimestamp" : "2021-09-16T21:07:34.826Z"
|
||||
}
|
||||
],
|
||||
@@ -141,7 +141,7 @@
|
||||
"data" : [
|
||||
{
|
||||
"stringValue" : "20210809.0.1",
|
||||
"endTimestamp" : "2021-09-16T21:07:34.826Z",
|
||||
"endTimestamp" : "2021-09-16T21:08:10.000Z",
|
||||
"startTimestamp" : "2021-09-16T21:07:34.826Z"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -164,6 +164,10 @@ NSDictionary *validMetricsDict = nil;
|
||||
}
|
||||
|
||||
- (void)testWritingMonarchJSONToAFile {
|
||||
id classMock = OCMClassMock([NSDate class]);
|
||||
OCMStub([classMock date])
|
||||
.andReturn([NSDate dateWithTimeIntervalSince1970:1631826490]); // 2021-09-16 21:08:10Z
|
||||
|
||||
OCMStub([self.mockConfigurator exportMetrics]).andReturn(YES);
|
||||
OCMStub([self.mockConfigurator metricFormat]).andReturn(SNTMetricFormatTypeMonarchJSON);
|
||||
OCMStub([self.mockConfigurator metricURL]).andReturn(self.jsonURL);
|
||||
|
||||
@@ -120,6 +120,17 @@ santa_unit_test(
|
||||
],
|
||||
)
|
||||
|
||||
santa_unit_test(
|
||||
name = "NSDataZlibTest",
|
||||
srcs = [
|
||||
"NSData+Zlib.h",
|
||||
"NSData+Zlib.m",
|
||||
"NSDataZlibTest.m",
|
||||
],
|
||||
resources = glob(["testdata/sync_preflight_basic.*"]),
|
||||
sdk_dylibs = ["libz"],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "broadcaster_lib",
|
||||
srcs = ["SNTSyncBroadcaster.m"],
|
||||
@@ -171,6 +182,7 @@ macos_command_line_application(
|
||||
test_suite(
|
||||
name = "unit_tests",
|
||||
tests = [
|
||||
":NSDataZlibTest",
|
||||
":SNTSyncTest",
|
||||
],
|
||||
visibility = ["//:santa_package_group"],
|
||||
|
||||
54
Source/santasyncservice/NSDataZlibTest.m
Normal file
@@ -0,0 +1,54 @@
|
||||
/// Copyright 2022 Google Inc. All rights reserved.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// http://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 <XCTest/XCTest.h>
|
||||
|
||||
#import "Source/santasyncservice/NSData+Zlib.h"
|
||||
|
||||
@interface NSDataZlibTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation NSDataZlibTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (NSData *)dataFromFixture:(NSString *)file {
|
||||
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:file ofType:nil];
|
||||
XCTAssertNotNil(path, @"failed to load testdata: %@", file);
|
||||
return [NSData dataWithContentsOfFile:path];
|
||||
}
|
||||
|
||||
- (void)testZlibCompressed {
|
||||
NSData *sut = [self dataFromFixture:@"sync_preflight_basic.json"];
|
||||
NSData *want = [self dataFromFixture:@"sync_preflight_basic.z"];
|
||||
|
||||
XCTAssertEqualObjects([sut zlibCompressed], want);
|
||||
}
|
||||
|
||||
- (void)testGzipCompressed {
|
||||
NSData *sut = [self dataFromFixture:@"sync_preflight_basic.json"];
|
||||
NSData *want = [self dataFromFixture:@"sync_preflight_basic.gz"];
|
||||
|
||||
XCTAssertEqualObjects([sut gzipCompressed], want);
|
||||
}
|
||||
|
||||
- (void)testCompressEmpty {
|
||||
NSData *sut = [NSData data];
|
||||
XCTAssertNil([sut zlibCompressed]);
|
||||
XCTAssertNil([sut gzipCompressed]);
|
||||
};
|
||||
|
||||
@end
|
||||
@@ -468,4 +468,36 @@
|
||||
OCMVerify([self.daemonConnRop databaseRuleAddRules:rules cleanSlate:NO reply:OCMOCK_ANY]);
|
||||
}
|
||||
|
||||
#pragma mark - SNTSyncPostflight Tests
|
||||
|
||||
- (void)testPostflightBasicResponse {
|
||||
[self setupDefaultDaemonConnResponses];
|
||||
SNTSyncPostflight *sut = [[SNTSyncPostflight alloc] initWithState:self.syncState];
|
||||
|
||||
[self stubRequestBody:nil response:nil error:nil validateBlock:nil];
|
||||
|
||||
XCTAssertTrue([sut sync]);
|
||||
OCMVerify([self.daemonConnRop setFullSyncLastSuccess:OCMOCK_ANY reply:OCMOCK_ANY]);
|
||||
|
||||
self.syncState.clientMode = SNTClientModeMonitor;
|
||||
XCTAssertTrue([sut sync]);
|
||||
OCMVerify([self.daemonConnRop setClientMode:SNTClientModeMonitor reply:OCMOCK_ANY]);
|
||||
|
||||
self.syncState.cleanSync = YES;
|
||||
XCTAssertTrue([sut sync]);
|
||||
OCMVerify([self.daemonConnRop setSyncCleanRequired:NO reply:OCMOCK_ANY]);
|
||||
|
||||
self.syncState.allowlistRegex = @"^horse$";
|
||||
self.syncState.blocklistRegex = @"^donkey$";
|
||||
XCTAssertTrue([sut sync]);
|
||||
OCMVerify([self.daemonConnRop setAllowedPathRegex:@"^horse$" reply:OCMOCK_ANY]);
|
||||
OCMVerify([self.daemonConnRop setBlockedPathRegex:@"^donkey$" reply:OCMOCK_ANY]);
|
||||
|
||||
self.syncState.blockUSBMount = YES;
|
||||
self.syncState.remountUSBMode = @[ @"readonly" ];
|
||||
XCTAssertTrue([sut sync]);
|
||||
OCMVerify([self.daemonConnRop setBlockUSBMount:YES reply:OCMOCK_ANY]);
|
||||
OCMVerify([self.daemonConnRop setRemountUSBMode:@[ @"readonly" ] reply:OCMOCK_ANY]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
BIN
Source/santasyncservice/testdata/sync_preflight_basic.gz
vendored
Normal file
BIN
Source/santasyncservice/testdata/sync_preflight_basic.z
vendored
Normal file
@@ -7,7 +7,10 @@ function main() {
|
||||
find $GIT_ROOT \( -name "*.m" -o -name "*.h" -name "*.mm" \) -exec clang-format --Werror --dry-run {} \+
|
||||
err="$(( $err | $? ))"
|
||||
|
||||
go get github.com/bazelbuild/buildtools/buildifier
|
||||
! git grep -EIn $'[ \t]+$'
|
||||
err="$(( $err | $? ))"
|
||||
|
||||
go install github.com/bazelbuild/buildtools/buildifier@latest
|
||||
~/go/bin/buildifier --lint=warn -r $GIT_ROOT
|
||||
err="$(( $err | $? ))"
|
||||
return $err
|
||||
|
||||
@@ -5,7 +5,7 @@ parent: Concepts
|
||||
# Rules
|
||||
|
||||
Rules provide the primary evaluation mechanism for allowing and blocking
|
||||
binaries with Santa on macOS. There are three types of rules: binary,
|
||||
binaries with Santa on macOS. There are three types of rules: binary,
|
||||
certificate, and TeamID.
|
||||
|
||||
##### Binary Rules
|
||||
@@ -67,8 +67,8 @@ SHA-256 hash.
|
||||
##### Apple Developer Team ID Rules
|
||||
The Apple Developer Program Team ID is a 10-character identifier issued by Apple
|
||||
and tied to developer accounts/organizations. This is distinct from Certificates,
|
||||
as a single developer account can and frequently will request/rotate between
|
||||
multiple different signing certificates and entitlements. This is an even more
|
||||
as a single developer account can and frequently will request/rotate between
|
||||
multiple different signing certificates and entitlements. This is an even more
|
||||
powerful rule with broader reach than individual certificate rules.
|
||||
|
||||
##### Rule Evaluation
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<integer>1</integer>
|
||||
<key>EnablePageZeroProtection</key>
|
||||
<false/>
|
||||
<key>EnableSilentMode</key>
|
||||
<false/>
|
||||
<key>EventDetailText</key>
|
||||
<string>Open sync server</string>
|
||||
<key>EventDetailURL</key>
|
||||
@@ -40,6 +42,36 @@
|
||||
<string>Entering Monitor mode<br/>Please be careful!</string>
|
||||
<key>MoreInfoURL</key>
|
||||
<string>https://sync-server-hostname/moreinfo</string>
|
||||
<key>StaticRules</key>
|
||||
<array>
|
||||
<dict>
|
||||
<!-- Always allow files signed by Google LLC -->
|
||||
<key>identifier</key>
|
||||
<string>EQHXZ8M8AV</string>
|
||||
<key>policy</key>
|
||||
<string>ALLOWLIST</string>
|
||||
<key>rule_type</key>
|
||||
<string>TEAMID</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<!-- Always allow files signed by "Internal Tools Certificate" -->
|
||||
<key>identifier</key>
|
||||
<string>b2617611fb6c008bfe9e05b7a633d4f21c403a0a1a88b514a04c3e5e111be025</string>
|
||||
<key>policy</key>
|
||||
<string>ALLOWLIST</string>
|
||||
<key>rule_type</key>
|
||||
<string>CERTIFICATE</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<!-- Always BLOCK the BundleExample.app binary in Santa's testdata files, for testing -->
|
||||
<key>identifier</key>
|
||||
<string>b7c1e3fd640c5f211c89b02c2c6122f78ce322aa5c56eb0bb54bc422a8f8b670</string>
|
||||
<key>policy</key>
|
||||
<string>BLOCKLIST</string>
|
||||
<key>rule_type</key>
|
||||
<string>BINARY</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>SyncBaseURL</key>
|
||||
<string>https://sync-server-hostname/api/santa/</string>
|
||||
<key>UnknownBlockMessage</key>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Configuration
|
||||
parent: Deployment
|
||||
nav_order: 2
|
||||
nav_order: 3
|
||||
---
|
||||
|
||||
# Configuration
|
||||
@@ -30,6 +30,7 @@ also known as mobileconfig files, which are in an Apple-specific XML format.
|
||||
| EnableBadSignatureProtection | Bool | Enable bad signature protection, defaults to NO. If this flag is set to YES, binaries with a bad signing chain will be blocked even in MONITOR mode, **unless** the binary is allowed by an explicit rule. |
|
||||
| EnablePageZeroProtection | Bool | Enable `__PAGEZERO` protection, defaults to YES. If this flag is set to YES, 32-bit binaries that are missing the `__PAGEZERO` segment will be blocked even in MONITOR mode, **unless** the binary is allowed by an explicit rule. |
|
||||
| EnableSysxCache | Bool | Enables a secondary cache that ensures better performance when multiple EndpointSecurity system extensions are installed. Defaults to YES in 2021.8, defaults to NO in earlier versions. |
|
||||
| EnableSilentMode | Bool | If true, Santa will not post any GUI notifications. This can be a very confusing experience for users, use with caution. Defaults to NO. |
|
||||
| AboutText | String | The text to display when the user opens Santa.app. If unset, the default text will be displayed. |
|
||||
| MoreInfoURL | String | The URL to open when the user clicks "More Info..." when opening Santa.app. If unset, the button will not be displayed. |
|
||||
| EventDetailURL | String | See the [EventDetailURL](#eventdetailurl) section below. |
|
||||
@@ -215,7 +216,7 @@ ways to install configuration profiles:
|
||||
| enable\_bundles\* | Bool | If set to `True` the bundle scanning feature is enabled. Defaults to `False`. |
|
||||
| enable\_transitive\_rules | Bool | If set to `True` the transitive rule feature is enabled. Defaults to `False`. |
|
||||
| enable\_all\_event\_upload | Bool | If set to `True` the client will upload events for all executions, including those that are explicitly allowed. |
|
||||
| block\_usb\_mass\_storage | Bool | If set to 'True' blocking USB Mass storage feature is enabled. Defaults to `False`. |
|
||||
| block\_usb\_mass\_storage | Bool | If set to 'True' blocking USB Mass storage feature is enabled. Defaults to `False`. |
|
||||
| remount\_usb\_mode | Array | Array of strings for arguments to pass to mount -o (any of "rdonly", "noexec", "nosuid", "nobrowse", "noowners", "nodev", "async", "-j"). when forcibly remounting devices. No default. |
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ nav_order: 1
|
||||
|
||||
# Getting Started
|
||||
|
||||
This page shows you the process to get started with your deployment of Santa.
|
||||
This page shows you the process to get started with your deployment of Santa.
|
||||
|
||||
**Note:** You can combine each of the profiles listed in the following steps into a single profile containing the different payloads: configuration, TCC, system extension, and notifications.
|
||||
|
||||
@@ -14,13 +14,13 @@ This page shows you the process to get started with your deployment of Santa.
|
||||
|
||||
1. Create and install your Santa configuration profile to customize your deployment of Santa. See [Configuration](configuration.md) for a reference list of the available options and an [example profile](https://github.com/google/santa/blob/main/docs/deployment/com.google.santa.example.mobileconfig).
|
||||
|
||||
1. Install the TCC and system extension configuration profiles:
|
||||
1. Install the TCC and system extension configuration profiles:
|
||||
|
||||
- The TCC profile provides Santa the access it requires to read files anywhere on disk. See an [example TCC profile](https://github.com/google/santa/blob/main/docs/deployment/tcc.configuration-profile-policy.santa.example.mobileconfig).
|
||||
- The system extension profile allows Santa to run without approval from the user. See an [example system extension profile](https://github.com/google/santa/blob/main/docs/deployment/system-extension-policy.santa.example.mobileconfig).
|
||||
|
||||
1. (Optional) Customize and install the notification settings profile. This allows you to set up notifications to alert when Santa is switching [modes](../concepts/mode.md). See an [example notification settings profile](https://github.com/google/santa/blob/main/docs/deployment/notificationsettings.santa.example.mobileconfig).
|
||||
1. (Optional) Customize and install the notification settings profile. This allows you to set up notifications to alert when Santa is switching [modes](../concepts/mode.md). See an [example notification settings profile](https://github.com/google/santa/blob/main/docs/deployment/notificationsettings.santa.example.mobileconfig).
|
||||
|
||||
The notifications modified through this profile are different to the main Santa GUI pop-ups. To configure the [Santa GUI](../binaries/santa-gui.md) notifications, use the [configuration profile](configuration.md) (in step 2).
|
||||
|
||||
1. Install the latest Santa package from [GitHub](https://github.com/google/santa/releases) (where you can also find release notes). The package is distributed as a `PKG` wrapped inside a `DMG`, both of which are properly signed and can be validated.
|
||||
1. Install the latest Santa package from [GitHub](https://github.com/google/santa/releases) (where you can also find release notes). The package is distributed as a `PKG` wrapped inside a `DMG`, both of which are properly signed and can be validated.
|
||||
|
||||
26
docs/deployment/recommended-rollout-strategy.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Recommended Rollout Strategy
|
||||
parent: Deployment
|
||||
nav_order: 2
|
||||
---
|
||||
|
||||
# Recommended Rollout Strategy
|
||||
|
||||
We recommend the following strategy to rollout Santa to an existing fleet of machines. This approach can help avoid too much disruption during the process.
|
||||
|
||||
As part of this strategy, we recommend using a sync server with Santa. For a list of open-source sync servers, see the [Sync Servers](sync-servers.md) page.
|
||||
|
||||
1. Configure the sync server to assign all clients to `MONITOR` mode and ensure that [event](../concepts/events.md) collection is working. See [Sync Server Provided Configuration](configuration.md#sync-server-provided-configuration) for a list of the configuration options.
|
||||
|
||||
1. Deploy to all hosts. Ideally, the deployment is a slow process over a reasonable period of time. That is, an incremental deployment to small groups of machines depending on your fleet size with enough time to monitor and manage the deployment. A slower deployment will allow you to catch incompatibilities early in the rollout before a full deployment is complete.
|
||||
|
||||
1. Leave the client in [`MONITOR` mode](../concepts/mode.md) for a defined period of time to allow event collection to take place.
|
||||
|
||||
1. Analyze the incoming events uploaded by the client in order to determine which applications you need to allow list.
|
||||
|
||||
1. Create allow rules as appropriate based on the previous analysis. See [Rules](../concepts/rules.md) for more explanation and examples of setting up rules.
|
||||
|
||||
1. Continue to analyze as you deploy the allow rules. The aim is to ensure that the number of incoming events is manageable.
|
||||
|
||||
1. Slowly move clients to `LOCKDOWN` mode. If possible, use the analysis to guide which hosts you move. For example, if a host is not uploading any block events, it's a good candidate for switching modes.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Sync Servers
|
||||
parent: Deployment
|
||||
nav_order: 3
|
||||
nav_order: 4
|
||||
---
|
||||
|
||||
# Sync Servers
|
||||
|
||||
Santa's [SyncBaseURL](configuration.md#sync-base-url) configuration flag allows you to synchronize with a management server, which uploads events that have occurred on the machine and downloads new rules.
|
||||
Santa's [SyncBaseURL](configuration.md#sync-base-url) configuration flag allows you to synchronize with a management server, which uploads events that have occurred on the machine and downloads new rules.
|
||||
|
||||
There are several open-source servers you can sync with:
|
||||
|
||||
@@ -17,4 +17,4 @@ There are several open-source servers you can sync with:
|
||||
|
||||
Alternatively, `santactl` can configure rules locally without a sync server.
|
||||
|
||||
See the [Syncing Overview](../introduction/syncing-overview.md) page for an explanation of how syncing works in Santa.
|
||||
See the [Syncing Overview](../introduction/syncing-overview.md) page for an explanation of how syncing works in Santa.
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
parent: Deployment
|
||||
nav_order: 4
|
||||
nav_order: 5
|
||||
---
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
As kernel extensions have been considered deprecated for several OS releases,
|
||||
this page will cover troublshooting the system extension and related topics.
|
||||
this page will cover troublshooting the system extension and related topics.
|
||||
|
||||
## Confirming Status
|
||||
|
||||
While there's an entire page on [santactl](../binaries/santactl.md), it's one of the best ways to start
|
||||
While there's an entire page on [santactl](../binaries/santactl.md), it's one of the best ways to start
|
||||
determining the cause of an issue:
|
||||
|
||||
```sh
|
||||
@@ -58,4 +58,4 @@ question as described on the [santactl](../binaries/santactl.md) page.
|
||||
|
||||
Depending on the presence or implementation details of a sync server, there may
|
||||
be queues and a process for allowing binaries or updated developer certificates.
|
||||
Events may also be observable from the server
|
||||
Events may also be observable from the server
|
||||
|
||||
430
docs/development/sync-protocol.md
Normal file
@@ -0,0 +1,430 @@
|
||||
---
|
||||
title: Sync Protocol
|
||||
parent: Development
|
||||
---
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
This document describes the protocol between Santa and the sync server, also known as the sync protocol. Implementors should be able to use this to create their own sync servers.
|
||||
|
||||
## Background
|
||||
|
||||
Santa can be run and configured with a sync server. This allows an admin to
|
||||
easily configure and sync rules across a fleet of macOS systems. In addition to
|
||||
distributing rules, using a sync server enables an admin to override some local
|
||||
configuration options e.g. `LOCKDOWN` mode on both a fleet-wide and
|
||||
per-host basis.
|
||||
|
||||
# Protocol Overview
|
||||
|
||||
The sync protocol is an HTTP/JSON based protocol. As such it is
|
||||
assumed that both the server and client add `Content-Type` headers are set to
|
||||
`application/json`.
|
||||
|
||||
The sync protocol is client initiated and consists of 4 request-response
|
||||
transactions called stages, `preflight`, `eventupload`, `ruledownload`, and `postflight`.
|
||||
A sync may consist of all 4 stages, just the `eventupload` stage or just the `ruledownload` stage.
|
||||
|
||||
| Stage | What it Does |
|
||||
|---|---|
|
||||
| **Preflight** | Report current Santa settings and machine attributes to sync server & retrieve configuration settings |
|
||||
| **Event Upload** | Report new blockable events to the sync server |
|
||||
| **Rule Download** | Retrieves new rules |
|
||||
| **Postflight** | Reports stats |
|
||||
|
||||
If the server returns an HTTP status other than `200` for any stage than the sync stops and the next stage is not performed.
|
||||
|
||||
At a high level this looks like the following sequence:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
client ->> server: POST /preflight/<machine_id>
|
||||
server -->> client: preflight response (200)
|
||||
loop until all events are uploaded
|
||||
client ->> server: POST /eventupload/<machine_id>
|
||||
server -->> client: eventupload response (200)
|
||||
end
|
||||
loop until all rules are downloaded
|
||||
client ->> server: GET /ruledownload/<machine_id>
|
||||
server --> client: ruledownload response (200)
|
||||
end
|
||||
client ->> server: POST /postflight/<machine_id> request
|
||||
server -->> client: postflight response (200)
|
||||
```
|
||||
|
||||
Where `<machine_id>` is a unique string identifier for the client. By default
|
||||
Santa uses the hardware UUID. It may also be set using the [MachineID, MachineIDPlist, and MachineIDKey options](../deployment/configuration.md) in the
|
||||
configuration.
|
||||
|
||||
## Authentication
|
||||
|
||||
The protocol expects the client to authenticate the server via SSL/TLS. Additionally, a sync server may support client certificates and use mutual TLS.
|
||||
|
||||
## Stages
|
||||
|
||||
All URLs are of the form `/<stage_name>/<machine_id>`, e.g. the preflight URL is `/preflight/<machine_id>`.
|
||||
|
||||
### Preflight
|
||||
|
||||
The preflight stage is used by the client to report host information to the sync
|
||||
server and to retrieve a limited set of configuration settings from the server.
|
||||
These configuration options override the initial values set from the application
|
||||
configuration profile.
|
||||
|
||||
This follows the following transaction:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
client ->> server: POST /preflight/<machine_id>
|
||||
server -->> client: preflight response
|
||||
```
|
||||
|
||||
#### `preflight` Request
|
||||
The request consists of the following JSON keys:
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| serial_num | YES | string | The macOS serial number from IOKit `kIOPlatformSerialNumberKey` | "XXXZ30URLVDQ" |
|
||||
| hostname | YES | string | The FQDN hostname of the client | markowsky.example.com |
|
||||
| os_version | YES | string | The OS version of the client from /System/Library/CoreServices/SystemVersion.plist | 12.4 |
|
||||
| os_build | YES | string | The OS build from /System/Library/CoreServices/SystemVersion.plist | "21F5048e" |
|
||||
| model_identifier | NO | string | The model of the macOS system | |
|
||||
| santa_version | YES | string | 2022.3 |
|
||||
| primary_user | YES | string | The username | markowsky |
|
||||
| binary_rule_count | NO | int | Number of binary allow / deny rules the client has at time of sync| 1000 |
|
||||
| certificate_rule_count | NO | int | Number of certificate allow / deny rules the client has at time of sync | 3400 |
|
||||
| compiler_rule_count | NO | int | Number of compiler rules the client has time of sync |
|
||||
| transitive_rule_count | NO | int | Number of transitive rules the client has at the time of sync |
|
||||
| teamid_rule_count | NO | int | Number of TeamID rules the client has at the time of sync | 24 |
|
||||
| client_mode | YES | string | the mode the client is operating in, either "LOCKDOWN" or "MONITOR" | LOCKDOWN |
|
||||
| clean_sync | NO | bool | the client has requested that a clean sync of its rules from the server. | true |
|
||||
|
||||
|
||||
### Example preflight request JSON Payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"compiler_rule_count" : 14,
|
||||
"client_mode" : "MONITOR",
|
||||
"santa_version" : "2022.6",
|
||||
"serial_num" : "XXXZ30URLVDQ",
|
||||
"binary_rule_count" : 43676,
|
||||
"hostname" : "markowsky.example.com",
|
||||
"primary_user" : "markowsky",
|
||||
"certificate_rule_count" : 2364,
|
||||
"teamid_rule_count" : 0,
|
||||
"os_build" : "21F5048e",
|
||||
"transitive_rule_count" : 0,
|
||||
"os_version" : "12.4",
|
||||
"model_identifier" : "MacBookPro15,1",
|
||||
"clean_sync": true,
|
||||
}
|
||||
```
|
||||
|
||||
#### `preflight` Response
|
||||
|
||||
If all of the data is well formed, the server responds with an HTTP status code of 200 and provides a JSON response.
|
||||
|
||||
The JSON object has the following keys:
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| enable_bundles | NO | boolean | Enabled bundle scanning | true |
|
||||
| enable_transitive_rules | NO | boolean | Whether or not to enable transitive allowlisting | true |
|
||||
| batch_size | YES | integer | Number of events to upload at a time | 128 |
|
||||
| full_sync_interval | YES | integer | Number of seconds between full syncs | 600 |
|
||||
| client_mode | YES | string | Operating mode to set for the client | either "MONITOR" or "LOCKDOWN" |
|
||||
| allowed_path_regex | YES | list of strings | List of regular expressions to allow a binary to execute from a path | ["/Users/markowsk/foo/.*"] |
|
||||
| blocked_path_regex | YES | list of strings | List of regular expressions to block a binary from executing by path | ["/tmp/"] |
|
||||
| block_usb_mount | NO | boolean | Block USB mass storage devices | true |
|
||||
| remount_usb_mode | NO | string | Force USB mass storage devices to be remounted with the following permissions (see [configuration](../deployment/configuration.md)) | |
|
||||
| clean_sync | YES | boolean | Whether or not the rules should be dropped and synced entirely from the server | true |
|
||||
|
||||
#### Example Preflight Response Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"batch_size": 100,
|
||||
"client_mode": "MONITOR",
|
||||
"allowed_path_regex": null,
|
||||
"blocked_path_regex": null,
|
||||
"clean_sync": false,
|
||||
"bundles_enabled": true,
|
||||
"enable_transitive_rules": false
|
||||
}
|
||||
```
|
||||
|
||||
### EventUpload
|
||||
|
||||
After the `preflight` stage has completed the client then initiates the
|
||||
`eventupload` stage if it has any events to upload. If there aren't any events
|
||||
this stage is skipped.
|
||||
|
||||
It consists of the following transaction, that may be repeated until all events are uploaded.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
client ->> server: POST /eventupload/<machine_id>
|
||||
server -->> client: eventupload response
|
||||
```
|
||||
|
||||
#### `eventupload` Request
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| events | YES | list of event objects | list of events to upload | see example payload |
|
||||
|
||||
|
||||
##### Event Objects
|
||||
|
||||
:information_source: Events are explained in more depth in the [Events page](../concepts/events.md).
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| file_sha256 | YES | string | sha256 of the executable that was executed | "fc6679da622c3ff38933220b8e73c7322ecdc94b4570c50ecab0da311b292682" |
|
||||
| file_path | YES | string | Absolute file path to the executable that was blocked | "/tmp/foo" |
|
||||
| file_name | YES | string | Command portion of the path of the blocked executable | "foo" |
|
||||
| executing_user | YES | string | Username that executed the binary | "markowsky" |
|
||||
| execution_time | YES | int | Unix timestamp of when the execution occured | 23344234232 |
|
||||
| loggedin_users | NO | List of strings | list of usernames logged in according to utmp | ["markowsky"] |
|
||||
| current_sessions | YES | List of strings | list of user sessions | ["markowsky@console", "markowsky@ttys000"] |
|
||||
| decision | YES | string | The decision Santa made for this binary, BUNDLE_BINARY is used to preemptively report binaries in a bundle. **Must be one of the examples**.| "ALLOW_BINARY", "ALLOW_CERTIFICATE", "ALLOW_SCOPE", "ALLOW_TEAMID", "ALLOW_UNKNOWN", "BLOCK_BINARY", "BLOCK_CERTIFICATE", "BLOCK_SCOPE", "BLOCK_TEAMID", "BLOCK_UNKNOWN", "BUNDLE_BINARY" |
|
||||
| file_bundle_id | NO | string | The executable's containing bundle's identifier as specified in the Info.plist | "com.apple.safari" |
|
||||
| file_bundle_path | NO | string | The path that the bundle resids in | /Applications/Santa.app |
|
||||
| file_bundle_executable_rel_path | NO | string | The relative path of the binary within the Bundle | "Contents/MacOS/AppName" |
|
||||
| file_bundle_name | NO | string | The bundle's display name. | "Google Chrome" |
|
||||
| file_bundle_version | NO | string | The bundle version string | "9999.1.1" |
|
||||
| file_bundle_version_string | NO | string | Bundle short version string | "2.3.4" |
|
||||
| file_bundle_hash | NO | string | SHA256 hash of all executables in the bundle | "7466e3687f540bcb7792c6d14d5a186667dbe18a85021857b42effe9f0370805" |
|
||||
| file_bundle_hash_millis | NO | int | The time in milliseconds it took to find all of the binaries, hash and produce the bundle_hash | 1234775 |
|
||||
| pid | YES | int | Process id of the executable that was blocked | 1234 |
|
||||
| ppid | YES | int | Parent process id of the executable that was blocked | 456 |
|
||||
| parent_name | YES | Parent process short command name of the executable that was blocked | "bar" |
|
||||
| quarantine_data_url | NO | string | The actual URL of the quarantined item from the quarantine database that this binary was downloaded from | https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg |
|
||||
| quarantine_referer_url | NO | string | Referring URL that lead to the binary being downloaded if known. | https://www.google.com/chrome/downloads/ |
|
||||
| quarantine_timestamp | NO | int | Unix Timestamp of when the binary was downloaded or 0 if not quarantined | 0 |
|
||||
| quarantine_agent_bundle_id | NO | string | The bundle ID of the software that quarantined the binary | "com.apple.Safari" |
|
||||
| signing_chain | NO | list of signing chain objects | Certs used to code sign the executable | See next section |
|
||||
|
||||
##### Signing Chain Objects
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| sha256 | YES | string | sha256 of the certificate used to sign | "7ae80b9ab38af0c63a9a81765f434d9a7cd8f720eb6037ef303de39d779bc258" |
|
||||
| cn | YES | string | Common Name field of the certificate used to sign | "Apple Worldwide Developer Relations Certification Authority" |
|
||||
| org | YES | string | Org field of the certificate used to sign | "Google LLC" |
|
||||
| ou | YES | string | OU field of the certificate used to sign | "G3" |
|
||||
| valid_from | YES | int | Unix timestamp of when the cert was issued | 1647447514 |
|
||||
| valid_until | YES | int | Unix timestamp of when the cert expires | 1678983513 |
|
||||
|
||||
|
||||
##### `eventupload` Request Example Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [{
|
||||
"file_path": "\/Applications\/Santa.app\/Contents\/MacOS",
|
||||
"file_bundle_version": "9999.1.1",
|
||||
"parent_name": "launchd",
|
||||
"logged_in_users": [
|
||||
"markowsky"
|
||||
],
|
||||
"quarantine_timestamp": 0,
|
||||
"signing_chain": [{
|
||||
"cn": "Apple Development: Google Development (XXXXXXXXXX)",
|
||||
"valid_until": 1678983513,
|
||||
"org": "Google LLC",
|
||||
"valid_from": 1647447514,
|
||||
"ou": "XXXXXXXXXX",
|
||||
"sha256": "7ae80b9ab38af0c63a9a81765f434d9a7cd8f720eb6037ef303de39d779bc258"
|
||||
},
|
||||
{
|
||||
"cn": "Apple Worldwide Developer Relations Certification Authority",
|
||||
"valid_until": 1897776000,
|
||||
"org": "Apple Inc.",
|
||||
"valid_from": 1582136027,
|
||||
"ou": "G3",
|
||||
"sha256": "dcf21878c77f4198e4b4614f03d696d89c66c66008d4244e1b99161aac91601f"
|
||||
},
|
||||
{
|
||||
"cn": "Apple Root CA",
|
||||
"valid_until": 2054670036,
|
||||
"org": "Apple Inc.",
|
||||
"valid_from": 1146001236,
|
||||
"ou": "Apple Certification Authority",
|
||||
"sha256": "b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024"
|
||||
}
|
||||
],
|
||||
"file_bundle_name": "santasyncservice",
|
||||
"executing_user": "root",
|
||||
"ppid": 1,
|
||||
"file_bundle_path": "/Applications/Santa.app",
|
||||
"file_name": "santasyncservice",
|
||||
"execution_time": 1657764366.475035,
|
||||
"file_sha256": "8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85",
|
||||
"decision": "ALLOW_BINARY",
|
||||
"file_bundle_id": "com.google.santa.syncservice",
|
||||
"file_bundle_version_string": "9999.1.1",
|
||||
"pid": 2595,
|
||||
"current_sessions": [
|
||||
"markowsky@console",
|
||||
"markowsky@ttys000",
|
||||
"markowsky@ttys001",
|
||||
"markowsky@ttys003"
|
||||
],
|
||||
"team_id": "XXXXXXXXXX"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### `eventupload` Response
|
||||
|
||||
The server should reply with an HTTP 200 if the request was successfully received and processed.
|
||||
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| event_upload_bundle_binaries | NO | list of strings | An array of bundle hashes that the sync server needs to be uploaded | ["8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85"] |
|
||||
|
||||
##### `eventupload` Response Example Payload
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"event_upload_bundle_binaries": ["8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85"]
|
||||
}
|
||||
```
|
||||
|
||||
### Rule Download
|
||||
|
||||
After events have been uploaded to the sync server, the `ruledownload` stage begins in a full sync.
|
||||
|
||||
Like the previous stages this is a simple HTTP request response cycle like so:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
client ->> server: POST /ruledownload/<machine_id>
|
||||
server -->> client: ruledownload response
|
||||
```
|
||||
|
||||
If either the client or server requested a clean sync in the `preflight` stage, the client is expected to purge its existing rules and download new rules from the sync server.
|
||||
|
||||
If a clean sync was not requested by either the client or the sync service, then the sync service should only send new rules seen since the last time the client synced.
|
||||
|
||||
Santa applies rules idempoently and is designed to receive rules multiple times without issue.
|
||||
|
||||
#### `ruledownload` Request
|
||||
|
||||
This stage is initiated via an HTTP POST request to the URL `/ruledownload/<machine_id>`
|
||||
|
||||
| Key | Required | Type | Meaning |
|
||||
|---|---|---|---|
|
||||
| cursor | NO | string | a field used by the sync server to indicate where the next batch of rules should start |
|
||||
|
||||
|
||||
##### `ruledownload` Request Example Payload
|
||||
|
||||
On the first request the payload is an empty dictionary
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
In the `ruledownload` response a special field called `cursor` will exist if there are more rules to download from server. The value and form of this field is left to the sync server implementor. It is expected to be used to track where the next batch of rules should start.
|
||||
|
||||
On subsequent requests to the server the `cursor` field is sent with the value from the previous response e.g.
|
||||
|
||||
```json
|
||||
{"cursor":"CpgBChcKCnVwZGF0ZWRfZHQSCQjh94a58uLlAhJ5ahVzfmdvb2dsZS5jb206YXBwbm90aHJyYAsSCUJsb2NrYWJsZSJAMTczOThkYWQzZDAxZGRmYzllMmEwYjBiMWQxYzQyMjY1OWM2ZjA3YmU1MmY3ZjQ1OTVmNDNlZjRhZWI5MGI4YQwLEgRSdWxlGICA8MvA0tIJDBgAIAA="}
|
||||
```
|
||||
|
||||
#### `ruledownload` Response
|
||||
|
||||
When a `ruledownload` request is received, the sync server responds with a JSON object
|
||||
containing a list of rule objects and a cursor so the client can resume
|
||||
downloading if the rules need to be downloaded in multiple batches.
|
||||
|
||||
| Key | Required | Type | Meaning |
|
||||
|---|---|---|---|
|
||||
| cursor | NO | string | Used to continue a rule download in a future request |
|
||||
| rules | YES | list of Rule objects | List of rule objects (see next section). |
|
||||
|
||||
##### Rules Objects
|
||||
|
||||
|
||||
| Key | Required | Type | Meaning | Example Value |
|
||||
|---|---|---|---|---|
|
||||
| identifier | YES | string | The attribute of the binary the rule should match on e.g. the team ID of a binary or sha256 hash value | "ff2a7daa4c25cbd5b057e4471c6a22aba7d154dadfb5cce139c37cf795f41c9c" |
|
||||
| policy | YES | string | identifies the action to perform in response to the rule matching must be one of the examples. | "ALLOWLIST","ALLOWLIST_COMPILER", "BLOCKLIST", "REMOVE", "SILENT_BLOCKLIST" |
|
||||
| rule_type | YES | string | identifies the type of rule must be one of he examples | "BINARY", "CERTIFICATE", "TEAMID" |
|
||||
| custom_msg | NO | string | A custom message to display when the rule matches | "Hello" |
|
||||
| creation_time | NO | float64 | time the rule was created | 1573543803.349378 |
|
||||
| file_bundle_binary_count | NO | integer | The number of binaries in a bundle | 13 |
|
||||
| file_bundle_hash | NO | string | The SHA256 of all binaries in a bundle. | "7466e3687f540bcb7792c6d14d5a186667dbe18a85021857b42effe9f0370805" |
|
||||
|
||||
|
||||
##### Example `ruledownload` Response Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": [{
|
||||
"identifier": "ff2a7daa4c25cbd5b057e4471c6a22aba7d154dadfb5cce139c37cf795f41c9c",
|
||||
"rule_type": "CERTIFICATE",
|
||||
"policy": "BLOCKLIST",
|
||||
"custom_msg": "",
|
||||
"creation_time": 1573543803.349378
|
||||
}, {
|
||||
"identifier": "233e741538e1cdf4835b3f2662e372cf0c2694b7e20b4e4663559c7fb0a9f234",
|
||||
"rule_type": "BINARY",
|
||||
"policy": "ALLOWLIST",
|
||||
"custom_msg": "",
|
||||
"creation_time": 1573572118.380034,
|
||||
"file_bundle_binary_count": 13,
|
||||
"file_bundle_hash": "7466e3687f540bcb7792c6d14d5a186667dbe18a85021857b42effe9f0370805"
|
||||
},
|
||||
{
|
||||
"identifier": "EQHXZ8M8AV",
|
||||
"rule_type": "TEAMID",
|
||||
"policy": "ALLOWLIST",
|
||||
"custom_msg": "Allow Software Google's Team ID",
|
||||
"creation_time": 1576623399.151607,
|
||||
"file_bundle_binary_count": 7,
|
||||
"file_bundle_hash": "e4736dd3a731f5f71850984175c0ec54dcde06021af18f476eb480c707fbecda"
|
||||
}],
|
||||
"cursor": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXzfmdvb2dsZS5jb206YXBwbm90aHJyYAsSCUJsb2NrYWJsZSJANGYyYTA2MjY1ZjRiODQ2M2Y2YjI0MmNiZTMwMTNkMGZhNjlkNDUxNmI4OTU3Y2I3ZDAxZDcyMTJkM2NhZmZiNAwLEgRSdWxlGICA8Kehk9MKDBgAIAA="
|
||||
}
|
||||
```
|
||||
|
||||
### Postflight
|
||||
|
||||
The postflight stage is used for the client to inform the sync server that it has successfully finished syncing. After sending the request, the client is expected to update its internal state applying any configuration changes sent by the sync server during the preflight step.
|
||||
|
||||
This stage uses an HTTP POST request to the url `/postflight/<machine_id>`
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
client ->> server: POST /postflight/<machine_id>
|
||||
server -->> client: postflight response
|
||||
```
|
||||
|
||||
#### `postflight` Request
|
||||
|
||||
The request is empty and should not be parsed by the sync server.
|
||||
|
||||
#### `postflight` Response
|
||||
|
||||
The server should reply with an HTTP 200 if the request was successfully received and processed. Any message body is ignored by the client.
|
||||
|
||||
<div id="mermaidjs-code" style="visibility: hidden">
|
||||
<script src="https://unpkg.com/mermaid@9.1.3/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
mermaid.initialize({
|
||||
startOnLoad:true,
|
||||
theme: "forest",
|
||||
});
|
||||
window.mermaid.init(undefined, document.querySelectorAll('.language-mermaid'));
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -9,7 +9,9 @@ Santa is a binary authorization system for macOS. It consists of a system extens
|
||||
|
||||
It is named Santa because it keeps track of binaries that are naughty or nice.
|
||||
|
||||
## Features
|
||||
The project and the latest release is available on [**GitHub**](https://github.com/google/santa).
|
||||
|
||||
## Features
|
||||
|
||||
* [**Multiple modes:**](concepts/mode.md) In the default `MONITOR` mode, all binaries except those marked as blocked will be allowed to run, whilst being logged and recorded in the events database. In `LOCKDOWN` mode, only listed binaries are allowed to run.
|
||||
* [**Event logging:**](concepts/events.md) All binary launches are logged. When in either mode, all unknown or denied binaries are stored in the database to enable later aggregation.
|
||||
@@ -59,4 +61,4 @@ The following pages describe the main components that make up Santa:
|
||||
### Development
|
||||
|
||||
* [Building Santa](development/building.md): How to build and load Santa for testing on a development machine.
|
||||
* [Contributing](development/contributing.md): How to contribute a bug fix or new feature to Santa.
|
||||
* [Contributing](development/contributing.md): How to contribute a bug fix or new feature to Santa.
|
||||
|
||||
@@ -7,7 +7,7 @@ redirect_from:
|
||||
|
||||
# Binary Authorization Overview
|
||||
|
||||
NOTE: This doc is out-dated and will be updated soon. We don't rely on a Kernel
|
||||
NOTE: This doc is out-dated and will be updated soon. We don't rely on a Kernel
|
||||
Extension anymore.
|
||||
|
||||
#### Background
|
||||
@@ -49,7 +49,7 @@ documentation. This flow does not cover the logging component of Santa, see the
|
||||
`execve()` the same `vnode_id`, santa-driver will have that thread wait
|
||||
for the in-flight decision from santad. All subsequent `execve()`s for
|
||||
the same `vnode_id` will use the decision in the cache as explained
|
||||
in #2, until the cache is invalidated.
|
||||
in #2, until the cache is invalidated.
|
||||
* If the executing file is written to while any of the threads are waiting
|
||||
for a response the `ACTION_REQUEST_BINARY` entry is removed, forcing the
|
||||
decision-making process to be restarted.
|
||||
|
||||