mirror of
https://github.com/google/santa.git
synced 2026-01-22 04:28:11 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a6a32c1cf | ||
|
|
ce03611b52 | ||
|
|
bbe9f83878 | ||
|
|
40e6c6aa92 | ||
|
|
9f6ccf092a | ||
|
|
d4ba4b082f | ||
|
|
cce43829eb | ||
|
|
c1bfbac2fe |
36
Podfile.lock
36
Podfile.lock
@@ -1,15 +1,15 @@
|
||||
PODS:
|
||||
- FMDB (2.6.2):
|
||||
- FMDB/standard (= 2.6.2)
|
||||
- FMDB/standard (2.6.2)
|
||||
- MOLAuthenticatingURLSession (2.2):
|
||||
- MOLCertificate (~> 1.5)
|
||||
- MOLCertificate (1.5)
|
||||
- MOLCodesignChecker (1.5):
|
||||
- MOLCertificate (~> 1.3)
|
||||
- MOLFCMClient (1.3):
|
||||
- MOLAuthenticatingURLSession (~> 2.1)
|
||||
- OCMock (3.4)
|
||||
- FMDB (2.7.2):
|
||||
- FMDB/standard (= 2.7.2)
|
||||
- FMDB/standard (2.7.2)
|
||||
- MOLAuthenticatingURLSession (2.4):
|
||||
- MOLCertificate (~> 1.8)
|
||||
- MOLCertificate (1.8)
|
||||
- MOLCodesignChecker (1.9):
|
||||
- MOLCertificate (~> 1.8)
|
||||
- MOLFCMClient (1.7):
|
||||
- MOLAuthenticatingURLSession (~> 2.4)
|
||||
- OCMock (3.4.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- FMDB
|
||||
@@ -20,13 +20,13 @@ DEPENDENCIES:
|
||||
- OCMock
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a
|
||||
MOLAuthenticatingURLSession: 5a5e31eb73248c3e92c79b9a285f031194e8404c
|
||||
MOLCertificate: c39cae866d24d36fbc78032affff83d401b5384a
|
||||
MOLCodesignChecker: fc9c64147811d7b0d0739127003e0630dff9213a
|
||||
MOLFCMClient: 13d8b42db9d750e772f09cc38fc453922fece09f
|
||||
OCMock: 35ae71d6a8fcc1b59434d561d1520b9dd4f15765
|
||||
FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
|
||||
MOLAuthenticatingURLSession: c238aa1c9a7b1077eb39a6f40204bfe76a7d204e
|
||||
MOLCertificate: c999513316d511c69f290fbf313dfe8dca4ad592
|
||||
MOLCodesignChecker: 303c01755646a0045c97f9f0b0fe5945ead42130
|
||||
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
|
||||
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
|
||||
|
||||
PODFILE CHECKSUM: acd378b3727c923d912e09812da344f7375c14fe
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.4.0
|
||||
|
||||
15
README.md
15
README.md
@@ -15,7 +15,7 @@ execution decisions based on the contents of a SQLite database, a GUI agent that
|
||||
notifies the user in case of a block decision and a command-line utility for
|
||||
managing the system and synchronizing the database with a server.
|
||||
|
||||
Santa is not yet a 1.0. We're writing more tests, fixing bugs, working on TODOs
|
||||
Santa is not yet at 1.0. We're writing more tests, fixing bugs, working on TODOs
|
||||
and finishing up a security audit.
|
||||
|
||||
It is named Santa because it keeps track of binaries that are naughty or nice.
|
||||
@@ -29,21 +29,21 @@ The Santa docs are stored in the [Docs](https://github.com/google/santa/blob/mas
|
||||
Admin-Related Features
|
||||
========
|
||||
|
||||
* Multiple modes: In the default MONITOR mode, all binaries except
|
||||
* Multiple modes: In the default MONITOR mode, all binaries except
|
||||
those marked as blacklisted will be allowed to run, whilst being logged and recorded in the events database. In LOCKDOWN mode, only whitelisted binaries are
|
||||
allowed to run.
|
||||
|
||||
* Event logging: When the kext is loaded, all binary launches are logged.
|
||||
When in either mode, all unknown or denied binaries are stored in the database to enable later aggregation.
|
||||
|
||||
* Certificate-based rules, with override levels: Instead of relying on a binaries hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
|
||||
* Certificate-based rules, with override levels: Instead of relying on a binary's hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
|
||||
certificate. You can therefore trust/block all binaries by a given publisher that were signed with that cert across version updates. A
|
||||
binary can only be whitelisted by its certificate if its signature validates
|
||||
correctly, but a rule for a binaries fingerprint will override a decision for a
|
||||
correctly, but a rule for a binary's fingerprint will override a decision for a
|
||||
certificate; i.e. you can whitelist a certificate while blacklisting a binary
|
||||
signed with that certificate, or vice-versa.
|
||||
|
||||
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature as Managed Client for OS X's (the precursor to configuration profiles, which used the same implementation mechanism) Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and doesn't rely on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precendence.
|
||||
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature to that found in Managed Client (the precursor to configuration profiles, which used the same implementation mechanism), Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and not relying on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precendence.
|
||||
|
||||
* Failsafe cert rules: You cannot put in a deny rule that would block the certificate used to sign launchd, a.k.a. pid 1, and therefore all components used in macOS. The binaries in every OS update (and in some cases entire new versions) are therefore auto-whitelisted. This does not affect binaries from Apple's App Store, which use various certs that change regularly for common apps. Likewise, you cannot blacklist Santa itself, and Santa uses a distinct separate cert than other Google apps.
|
||||
|
||||
@@ -54,7 +54,7 @@ Santa is written with the intention of helping protect users from themselves.
|
||||
People often download malware and trust it, giving the malware credentials, or
|
||||
allowing unknown software to exfiltrate more data about your system. As a
|
||||
centrally managed component, Santa can help stop the spread of malware among a
|
||||
larger fleet of machines. Independently, Santa can aid in analyzing what is
|
||||
large fleet of machines. Independently, Santa can aid in analyzing what is
|
||||
running on your computer.
|
||||
|
||||
Santa is part of a defense-in-depth strategy, and you should continue to protect
|
||||
@@ -62,7 +62,6 @@ hosts in whatever other ways you see fit.
|
||||
|
||||
Get Help
|
||||
========
|
||||
|
||||
If you have questions or otherwise need help getting started, the
|
||||
[santa-dev](https://groups.google.com/forum/#!forum/santa-dev) group is a
|
||||
great place. Please consult the [wiki](https://github.com/google/santa/wiki) and [issues](https://github.com/google/santa/issues) as well.
|
||||
@@ -84,7 +83,7 @@ continue to work across OS versions.
|
||||
|
||||
Known Issues
|
||||
============
|
||||
Santa is not yet a 1.0 and we have some known issues to be aware of:
|
||||
Santa is not yet at 1.0 and we have some known issues to be aware of:
|
||||
|
||||
* Santa only blocks execution (execve and variants), it doesn't protect against
|
||||
dynamic libraries loaded with dlopen, libraries on disk that have been replaced, or
|
||||
|
||||
@@ -148,9 +148,6 @@
|
||||
0DEA5F7B1CF64C9200704398 /* sync_ruledownload_batch2.json in Resources */ = {isa = PBXBuildFile; fileRef = 0DEA5F781CF64C8B00704398 /* sync_ruledownload_batch2.json */; };
|
||||
0DEA5F7D1CF64EB600704398 /* SNTCommandSyncRuleDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */; };
|
||||
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */; };
|
||||
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
0DEFB7C61ACDE5F600B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
0DEFB7C81ACF0BFE00B92AAE /* SNTFileWatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */; };
|
||||
0DF395641AB76A7900CBC520 /* NSData+Zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DF395631AB76A7900CBC520 /* NSData+Zlib.m */; };
|
||||
0DF395661AB76ABC00CBC520 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0DF395651AB76ABC00CBC520 /* libz.dylib */; };
|
||||
168A4E09A2A5E0B7DF8A2F1A /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C11A10A5D6E112788769CF70 /* libPods-santad.a */; };
|
||||
@@ -171,8 +168,6 @@
|
||||
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */; };
|
||||
C776A1071DEE160500A56616 /* SNTCommandSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C776A1061DEE160500A56616 /* SNTCommandSyncManager.m */; };
|
||||
C78227631E1C3C7D006EB2D6 /* santabs.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = C78227541E1C3C58006EB2D6 /* santabs.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
C7943FE92028B855008D4F76 /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
C7943FEA2028C4F7008D4F76 /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
C795ED901D80A5BE007CFF42 /* SNTPolicyProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */; };
|
||||
C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */; };
|
||||
C79A23581E23F7E80037AFA8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C79A23561E23F7E80037AFA8 /* main.m */; };
|
||||
@@ -416,9 +411,6 @@
|
||||
0DEA5F781CF64C8B00704398 /* sync_ruledownload_batch2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = sync_ruledownload_batch2.json; sourceTree = "<group>"; };
|
||||
0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncConstants.m; sourceTree = "<group>"; };
|
||||
0DEFB7C11ACB28BC00B92AAE /* SNTCommandSyncConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncConstants.h; sourceTree = "<group>"; };
|
||||
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTFileWatcher.h; sourceTree = "<group>"; };
|
||||
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcher.m; sourceTree = "<group>"; };
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcherTest.m; sourceTree = "<group>"; };
|
||||
0DF395621AB76A7900CBC520 /* NSData+Zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Zlib.h"; sourceTree = "<group>"; };
|
||||
0DF395631AB76A7900CBC520 /* NSData+Zlib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Zlib.m"; sourceTree = "<group>"; };
|
||||
0DF395651AB76ABC00CBC520 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
@@ -540,7 +532,6 @@
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
|
||||
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
|
||||
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */,
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
|
||||
);
|
||||
@@ -733,8 +724,6 @@
|
||||
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */,
|
||||
0DCD6040190ACCB8006B445C /* SNTFileInfo.h */,
|
||||
0DCD6041190ACCB8006B445C /* SNTFileInfo.m */,
|
||||
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */,
|
||||
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */,
|
||||
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */,
|
||||
0D28E5E119269B3600280F87 /* SNTLogging.h */,
|
||||
0DA73C9E1934F8100056D7C4 /* SNTLogging.m */,
|
||||
@@ -1466,10 +1455,8 @@
|
||||
0DCD605819115E57006B445C /* SNTXPCControlInterface.m in Sources */,
|
||||
0D202D1A1CDD464B00A88F16 /* SNTCommandSyncPreflight.m in Sources */,
|
||||
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
0DEFB7C61ACDE5F600B92AAE /* SNTFileWatcher.m in Sources */,
|
||||
C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */,
|
||||
C72E8D941D7F399900C86DD3 /* SNTCommandFileInfoTest.m in Sources */,
|
||||
0DEFB7C81ACF0BFE00B92AAE /* SNTFileWatcherTest.m in Sources */,
|
||||
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */,
|
||||
0DE5B54C1C92722300C00603 /* SNTNotificationQueue.m in Sources */,
|
||||
0DEA5F651CF6057D00704398 /* SNTCommandSyncEventUpload.m in Sources */,
|
||||
@@ -1516,7 +1503,6 @@
|
||||
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */,
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
|
||||
C7943FE92028B855008D4F76 /* SNTFileWatcher.m in Sources */,
|
||||
0DB77FDA1CD14092004DF060 /* SNTBlockMessage.m in Sources */,
|
||||
0D35BDA218FD71CE00921A21 /* main.m in Sources */,
|
||||
0DCD6043190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
@@ -1535,7 +1521,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C7943FEA2028C4F7008D4F76 /* SNTFileWatcher.m in Sources */,
|
||||
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */,
|
||||
0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */,
|
||||
0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */,
|
||||
@@ -1583,7 +1568,6 @@
|
||||
0DE71A751B95F7F900518526 /* SNTCachedDecision.m in Sources */,
|
||||
C7FB56F61DBFB480004E14EF /* SNTXPCSyncdInterface.m in Sources */,
|
||||
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
|
||||
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */,
|
||||
0D7D01871774F93A005DBAB4 /* SNTDriverManager.m in Sources */,
|
||||
0D8E18CD19107B56000F89B8 /* SNTDaemonControlController.m in Sources */,
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
@import SecurityInterface.SFCertificatePanel;
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
#import "SNTBlockMessage.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTMessageWindow.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#import "SNTFileWatcher.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTStrengthify.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
@@ -32,9 +31,6 @@
|
||||
/// Holds the configurations from a sync server and mobileconfig.
|
||||
@property NSMutableDictionary *syncState;
|
||||
@property NSMutableDictionary *configState;
|
||||
|
||||
/// Watcher for the sync-state.plist.
|
||||
@property(nonatomic) SNTFileWatcher *syncStateWatcher;
|
||||
@end
|
||||
|
||||
@implementation SNTConfigurator
|
||||
@@ -86,40 +82,45 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
Class number = [NSNumber class];
|
||||
Class re = [NSRegularExpression class];
|
||||
Class date = [NSDate class];
|
||||
Class string = [NSString class];
|
||||
Class data = [NSData class];
|
||||
_syncServerKeyTypes = @{
|
||||
kClientModeKey : [NSNumber class],
|
||||
kWhitelistRegexKey : [NSRegularExpression class],
|
||||
kBlacklistRegexKey : [NSRegularExpression class],
|
||||
kFullSyncLastSuccess : [NSDate class],
|
||||
kRuleSyncLastSuccess : [NSDate class],
|
||||
kSyncCleanRequired : [NSNumber class]
|
||||
kClientModeKey : number,
|
||||
kWhitelistRegexKey : re,
|
||||
kBlacklistRegexKey : re,
|
||||
kFullSyncLastSuccess : date,
|
||||
kRuleSyncLastSuccess : date,
|
||||
kSyncCleanRequired : number
|
||||
};
|
||||
_forcedConfigKeyTypes = @{
|
||||
kClientModeKey : [NSNumber class],
|
||||
kFileChangesRegexKey : [NSRegularExpression class],
|
||||
kWhitelistRegexKey : [NSRegularExpression class],
|
||||
kBlacklistRegexKey : [NSRegularExpression class],
|
||||
kEnablePageZeroProtectionKey : [NSNumber class],
|
||||
kMoreInfoURLKey : [NSString class],
|
||||
kEventDetailURLKey : [NSString class],
|
||||
kEventDetailTextKey : [NSString class],
|
||||
kUnknownBlockMessage : [NSString class],
|
||||
kBannedBlockMessage : [NSString class],
|
||||
kModeNotificationMonitor : [NSString class],
|
||||
kModeNotificationLockdown : [NSString class],
|
||||
kSyncBaseURLKey : [NSString class],
|
||||
kClientAuthCertificateFileKey : [NSString class],
|
||||
kClientAuthCertificatePasswordKey : [NSString class],
|
||||
kClientAuthCertificateCNKey : [NSString class],
|
||||
kClientAuthCertificateIssuerKey : [NSString class],
|
||||
kServerAuthRootsDataKey : [NSData class],
|
||||
kServerAuthRootsFileKey : [NSString class],
|
||||
kMachineOwnerKey : [NSString class],
|
||||
kMachineIDKey : [NSString class],
|
||||
kMachineOwnerPlistFileKey : [NSString class],
|
||||
kMachineOwnerPlistKeyKey : [NSString class],
|
||||
kMachineIDPlistFileKey : [NSString class],
|
||||
kMachineIDPlistKeyKey : [NSString class],
|
||||
kClientModeKey : number,
|
||||
kFileChangesRegexKey : re,
|
||||
kWhitelistRegexKey : re,
|
||||
kBlacklistRegexKey : re,
|
||||
kEnablePageZeroProtectionKey : number,
|
||||
kMoreInfoURLKey : string,
|
||||
kEventDetailURLKey : string,
|
||||
kEventDetailTextKey : string,
|
||||
kUnknownBlockMessage : string,
|
||||
kBannedBlockMessage : string,
|
||||
kModeNotificationMonitor : string,
|
||||
kModeNotificationLockdown : string,
|
||||
kSyncBaseURLKey : string,
|
||||
kClientAuthCertificateFileKey : string,
|
||||
kClientAuthCertificatePasswordKey : string,
|
||||
kClientAuthCertificateCNKey : string,
|
||||
kClientAuthCertificateIssuerKey : string,
|
||||
kServerAuthRootsDataKey : data,
|
||||
kServerAuthRootsFileKey : string,
|
||||
kMachineOwnerKey : string,
|
||||
kMachineIDKey : string,
|
||||
kMachineOwnerPlistFileKey : string,
|
||||
kMachineOwnerPlistKeyKey : string,
|
||||
kMachineIDPlistFileKey : string,
|
||||
kMachineIDPlistKeyKey : string,
|
||||
};
|
||||
_defaults = [NSUserDefaults standardUserDefaults];
|
||||
[_defaults addSuiteNamed:@"com.google.santa"];
|
||||
@@ -141,94 +142,129 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
return sharedConfigurator;
|
||||
}
|
||||
|
||||
+ (NSSet *)syncAndConfigStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [[self syncStateSet] setByAddingObjectsFromSet:[self configStateSet]];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (NSSet *)syncStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSSet setWithObject:NSStringFromSelector(@selector(syncState))];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (NSSet *)configStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSSet setWithObject:NSStringFromSelector(@selector(configState))];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
#pragma mark KVO Dependencies
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingClientMode {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingWhitelistPathRegex {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingBlacklistPathRegex {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingFileChangesRegex {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncBaseURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEnablePageZeroProtection {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMoreInfoURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEventDetailURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEventDetailText {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingUnknownBlockMessage {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingBannedBlockMessage {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingModeNotificationMonitor {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingModeNotificationLockdown {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateFile {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificatePassword {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateCn {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateIssuer {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsData {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsFile {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingFullSyncLastSuccess {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMachineOwner {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMachineID {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingFullSyncLastSuccess {
|
||||
return [self syncStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingRuleSyncLastSuccess {
|
||||
return [self syncStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncCleanRequired {
|
||||
return [self syncStateSet];
|
||||
}
|
||||
|
||||
#pragma mark Public Interface
|
||||
@@ -344,7 +380,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setFullSyncLastSuccess:(NSDate *)fullSyncLastSuccess {
|
||||
self.syncState[kFullSyncLastSuccess] = fullSyncLastSuccess;
|
||||
[self updateSyncStateForKey:kFullSyncLastSuccess value:fullSyncLastSuccess];
|
||||
self.ruleSyncLastSuccess = fullSyncLastSuccess;
|
||||
}
|
||||
|
||||
@@ -353,8 +389,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setRuleSyncLastSuccess:(NSDate *)ruleSyncLastSuccess {
|
||||
self.syncState[kRuleSyncLastSuccess] = ruleSyncLastSuccess;
|
||||
[self saveSyncStateToDisk];
|
||||
[self updateSyncStateForKey:kRuleSyncLastSuccess value:ruleSyncLastSuccess];
|
||||
}
|
||||
|
||||
- (BOOL)syncCleanRequired {
|
||||
@@ -362,8 +397,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setSyncCleanRequired:(BOOL)syncCleanRequired {
|
||||
self.syncState[kSyncCleanRequired] = @(syncCleanRequired);
|
||||
[self saveSyncStateToDisk];
|
||||
[self updateSyncStateForKey:kSyncCleanRequired value:@(syncCleanRequired)];
|
||||
}
|
||||
|
||||
- (NSString *)machineOwner {
|
||||
@@ -400,12 +434,13 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
///
|
||||
/// Update the syncState. Triggers a KVO event for all dependents.
|
||||
///
|
||||
- (BOOL)updateSyncStateForKey:(NSString *)key value:(id)value {
|
||||
NSMutableDictionary *syncState = self.syncState.mutableCopy;
|
||||
syncState[key] = value;
|
||||
self.syncState = syncState;
|
||||
[self saveSyncStateToDisk];
|
||||
return YES;
|
||||
- (void)updateSyncStateForKey:(NSString *)key value:(id)value {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSMutableDictionary *syncState = self.syncState.mutableCopy;
|
||||
syncState[key] = value;
|
||||
self.syncState = syncState;
|
||||
[self saveSyncStateToDisk];
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
@@ -427,15 +462,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
WEAKIFY(self);
|
||||
self.syncStateWatcher = [[SNTFileWatcher alloc] initWithFilePath:kSyncStateFilePath
|
||||
handler:^(unsigned long data) {
|
||||
STRONGIFY(self);
|
||||
[self syncStateFileChanged:data];
|
||||
}];
|
||||
});
|
||||
return syncState;
|
||||
}
|
||||
|
||||
@@ -456,39 +482,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
ofItemAtPath:kSyncStateFilePath error:NULL];
|
||||
}
|
||||
|
||||
///
|
||||
/// Ensure permissions are 0644.
|
||||
/// Revert any out-of-band changes.
|
||||
///
|
||||
- (void)syncStateFileChanged:(unsigned long)data {
|
||||
if (data & DISPATCH_VNODE_ATTRIB) {
|
||||
const char *cPath = [kSyncStateFilePath fileSystemRepresentation];
|
||||
struct stat fileStat;
|
||||
stat(cPath, &fileStat);
|
||||
int mask = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int desired = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
if (fileStat.st_uid != 0 || fileStat.st_gid != 0 || (fileStat.st_mode & mask) != desired) {
|
||||
LOGI(@"Sync state file permissions changed, fixing.");
|
||||
chown(cPath, 0, 0);
|
||||
chmod(cPath, desired);
|
||||
}
|
||||
} else {
|
||||
NSDictionary *newSyncState = [self readSyncStateFromDisk];
|
||||
for (NSString *key in self.syncState) {
|
||||
if (((self.syncState[key] && !newSyncState[key]) ||
|
||||
(!self.syncState[key] && newSyncState[key]) ||
|
||||
(self.syncState[key] && ![self.syncState[key] isEqualTo:newSyncState[key]]))) {
|
||||
// Ignore sync url and dates
|
||||
if ([key isEqualToString:kRuleSyncLastSuccess] ||
|
||||
[key isEqualToString:kFullSyncLastSuccess]) continue;
|
||||
LOGE(@"Sync state file changed, replacing");
|
||||
[self saveSyncStateToDisk];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearSyncState {
|
||||
self.syncState = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/// Copyright 2015 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 Foundation;
|
||||
|
||||
///
|
||||
/// Simple file watching class using dispatch sources. Will automatically
|
||||
/// reload the watch if the file is deleted and continue watching for
|
||||
/// events until deallocated.
|
||||
///
|
||||
@interface SNTFileWatcher : NSObject
|
||||
|
||||
///
|
||||
/// Designated initializer
|
||||
/// Initializes the watcher and begins watching for modifications.
|
||||
///
|
||||
/// @param filePath the file to watch.
|
||||
/// @param handler the handler to call when changes happen. The argument to the block is the
|
||||
/// type of change that happened as a bitmask to be compared with DISPATCH_VNODE_* constants.
|
||||
///
|
||||
- (nonnull instancetype)initWithFilePath:(nonnull NSString *)filePath
|
||||
handler:(nonnull void (^)(unsigned long))handler;
|
||||
|
||||
@end
|
||||
@@ -1,94 +0,0 @@
|
||||
/// Copyright 2015 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 "SNTFileWatcher.h"
|
||||
|
||||
#import "SNTStrengthify.h"
|
||||
|
||||
@interface SNTFileWatcher ()
|
||||
@property NSString *filePath;
|
||||
@property(copy) void (^handler)(unsigned long);
|
||||
|
||||
@property dispatch_source_t source;
|
||||
@end
|
||||
|
||||
@implementation SNTFileWatcher
|
||||
|
||||
- (instancetype)init {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFilePath:(nonnull NSString *)filePath
|
||||
handler:(nonnull void (^)(unsigned long))handler {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_filePath = filePath;
|
||||
_handler = handler;
|
||||
[self startWatchingFile];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self stopWatchingFile];
|
||||
}
|
||||
|
||||
- (void)startWatchingFile {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
|
||||
int mask = (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME |
|
||||
DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB);
|
||||
|
||||
dispatch_async(queue, ^{
|
||||
int fd = -1;
|
||||
const char *filePath = [self.filePath fileSystemRepresentation];
|
||||
while ((fd = open(filePath, O_EVTONLY | O_CLOEXEC)) < 0) {
|
||||
usleep(200000); // wait 200ms
|
||||
}
|
||||
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, mask, queue);
|
||||
|
||||
WEAKIFY(self);
|
||||
|
||||
dispatch_source_set_event_handler(self.source, ^{
|
||||
STRONGIFY(self);
|
||||
unsigned long data = dispatch_source_get_data(self.source);
|
||||
self.handler(data);
|
||||
if (data & DISPATCH_VNODE_DELETE || data & DISPATCH_VNODE_RENAME) {
|
||||
[self stopWatchingFile];
|
||||
[self startWatchingFile];
|
||||
}
|
||||
sleep(2);
|
||||
});
|
||||
|
||||
dispatch_source_set_registration_handler(self.source, ^{
|
||||
STRONGIFY(self);
|
||||
self.handler(0);
|
||||
});
|
||||
|
||||
dispatch_source_set_cancel_handler(self.source, ^{
|
||||
close(fd);
|
||||
});
|
||||
|
||||
dispatch_resume(self.source);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopWatchingFile {
|
||||
if (!self.source) return;
|
||||
dispatch_source_set_event_handler_f(self.source, NULL);
|
||||
dispatch_source_cancel(self.source);
|
||||
self.source = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -66,7 +66,7 @@ typedef enum {
|
||||
ACTION_RESPOND_DENY = 21,
|
||||
ACTION_RESPOND_TOOLONG = 22,
|
||||
ACTION_RESPOND_ACK = 23,
|
||||
|
||||
|
||||
// NOTIFY
|
||||
ACTION_NOTIFY_EXEC = 30,
|
||||
ACTION_NOTIFY_WRITE = 31,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
@implementation SNTStoredEvent
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import "SNTXPCConnection.h"
|
||||
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTStrengthify.h"
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import <pthread/pthread.h>
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
@@ -72,18 +72,18 @@
|
||||
}
|
||||
|
||||
- (void)attemptReconnection {
|
||||
[self performSelectorInBackground:@selector(createConnection) withObject:nil];
|
||||
[self performSelectorOnMainThread:@selector(createConnection) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
|
||||
#pragma mark SNTBundleServiceXPC Methods
|
||||
|
||||
// Connect to the SantaGUI
|
||||
- (void)setBundleNotificationListener:(NSXPCListenerEndpoint *)listener {
|
||||
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
|
||||
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
|
||||
[c resume];
|
||||
self.notifierConnection = c;
|
||||
dispatch_async(self.queue, ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
|
||||
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
|
||||
[c resume];
|
||||
self.notifierConnection = c;
|
||||
[self createConnection];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,10 +345,11 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
dispatch_once(&token, ^{ [cmd.daemonConn resume]; });
|
||||
__block SNTEventState state;
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
|
||||
NSError *err;
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:&err];
|
||||
[[cmd.daemonConn remoteObjectProxy] decisionForFilePath:fileInfo.path
|
||||
fileSHA256:fileInfo.SHA256
|
||||
certificateSHA256:csc.leafCertificate.SHA256
|
||||
certificateSHA256:err ? nil : csc.leafCertificate.SHA256
|
||||
reply:^(SNTEventState s) {
|
||||
state = s;
|
||||
dispatch_semaphore_signal(sema);
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
#import "SNTCommand.h"
|
||||
#import "SNTCommandController.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTFileInfo.h"
|
||||
|
||||
@@ -178,7 +178,7 @@ static void reachabilityHandler(
|
||||
}
|
||||
|
||||
- (void)isFCMListening:(void (^)(BOOL))reply {
|
||||
reply((self.FCMClient.FCMToken != nil));
|
||||
reply(self.FCMClient.isConnected);
|
||||
}
|
||||
|
||||
#pragma mark push notification methods
|
||||
@@ -205,16 +205,17 @@ static void reachabilityHandler(
|
||||
[self processFCMMessage:message withMachineID:machineID];
|
||||
}];
|
||||
|
||||
self.FCMClient.connectionErrorHandler = ^(NSError *error) {
|
||||
self.FCMClient.connectionErrorHandler = ^(NSHTTPURLResponse *response, NSError *error) {
|
||||
STRONGIFY(self);
|
||||
LOGE(@"FCM connection error: %@", error);
|
||||
if (response) LOGE(@"FCM fatal response: %@", response);
|
||||
if (error) LOGE(@"FCM fatal error: %@", error);
|
||||
[self.FCMClient disconnect];
|
||||
self.FCMClient = nil;
|
||||
[self rescheduleTimerQueue:self.fullSyncTimer secondsFromNow:kDefaultFullSyncInterval];
|
||||
};
|
||||
|
||||
self.FCMClient.loggingBlock = ^(NSString *log) {
|
||||
LOGD(@"%@", log);
|
||||
LOGD(@"FCMClient: %@", log);
|
||||
};
|
||||
|
||||
[self.FCMClient connect];
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
#import "SNTEventTable.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@implementation SNTEventTable
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
|
||||
#import "SNTRuleTable.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTRule.h"
|
||||
|
||||
@@ -80,22 +80,23 @@
|
||||
|
||||
// Listen for actionable config changes.
|
||||
NSKeyValueObservingOptions bits = (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld);
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"clientMode"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"syncBaseURL"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"whitelistPathRegex"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"blacklistPathRegex"
|
||||
options:bits
|
||||
context:NULL];
|
||||
SNTConfigurator *configurator = [SNTConfigurator configurator];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(clientMode))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(syncBaseURL))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(whitelistPathRegex))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(blacklistPathRegex))
|
||||
options:bits
|
||||
context:NULL];
|
||||
|
||||
// Establish XPC listener for Santa and santactl connections
|
||||
SNTDaemonControlController *dc =
|
||||
@@ -270,23 +271,25 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSString *,id> *)change
|
||||
context:(void *)context {
|
||||
if ([keyPath isEqualToString:@"clientMode"]) {
|
||||
NSString *newKey = NSKeyValueChangeNewKey;
|
||||
NSString *oldKey = NSKeyValueChangeOldKey;
|
||||
if ([keyPath isEqualToString:NSStringFromSelector(@selector(clientMode))]) {
|
||||
SNTClientMode new =
|
||||
[change[@"new"] isKindOfClass:[NSNumber class]] ? [change[@"new"] longLongValue] : 0;
|
||||
[change[newKey] isKindOfClass:[NSNumber class]] ? [change[newKey] longLongValue] : 0;
|
||||
SNTClientMode old =
|
||||
[change[@"old"] isKindOfClass:[NSNumber class]] ? [change[@"old"] longLongValue] : 0;
|
||||
[change[oldKey] isKindOfClass:[NSNumber class]] ? [change[oldKey] longLongValue] : 0;
|
||||
if (new != old) [self clientModeDidChange:new];
|
||||
} else if ([keyPath isEqualToString:@"syncBaseURL"]) {
|
||||
NSURL *new = [change[@"new"] isKindOfClass:[NSURL class]] ? change[@"new"] : nil;
|
||||
NSURL *old = [change[@"old"] isKindOfClass:[NSURL class]] ? change[@"old"] : nil;
|
||||
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(syncBaseURL))]) {
|
||||
NSURL *new = [change[newKey] isKindOfClass:[NSURL class]] ? change[newKey] : nil;
|
||||
NSURL *old = [change[oldKey] isKindOfClass:[NSURL class]] ? change[oldKey] : nil;
|
||||
if (!new && !old) return;
|
||||
if (![new.absoluteString isEqualToString:old.absoluteString]) [self syncBaseURLDidChange:new];
|
||||
} else if ([keyPath isEqualToString:@"whitelistPathRegex"] ||
|
||||
[keyPath isEqualToString:@"blacklistPathRegex"]) {
|
||||
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(whitelistPathRegex))] ||
|
||||
[keyPath isEqualToString:NSStringFromSelector(@selector(blacklistPathRegex))]) {
|
||||
NSRegularExpression *new =
|
||||
[change[@"new"] isKindOfClass:[NSRegularExpression class]] ? change[@"new"] : nil;
|
||||
[change[newKey] isKindOfClass:[NSRegularExpression class]] ? change[newKey] : nil;
|
||||
NSRegularExpression *old =
|
||||
[change[@"old"] isKindOfClass:[NSRegularExpression class]] ? change[@"old"] : nil;
|
||||
[change[oldKey] isKindOfClass:[NSRegularExpression class]] ? change[oldKey] : nil;
|
||||
if (!new && !old) return;
|
||||
if (![new.pattern isEqualToString:old.pattern]) {
|
||||
LOGI(@"Changed [white|black]list regex, flushing cache");
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#include <pwd.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
#import "SNTCachedDecision.h"
|
||||
#import "SNTCommonEnums.h"
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTBlockMessage.h"
|
||||
#import "SNTCachedDecision.h"
|
||||
#import "SNTCommonEnums.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#import "SNTCommonEnums.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
|
||||
#import <MOLCertificate.h>
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
@class SNTCachedDecision;
|
||||
@class SNTFileInfo;
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
///
|
||||
- (NSString *)fileIsScopeWhitelisted:(SNTFileInfo *)fi {
|
||||
if (!fi) return nil;
|
||||
|
||||
|
||||
// Determine if file is within a whitelisted path
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] whitelistPathRegex];
|
||||
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
- (NSString *)fileIsScopeBlacklisted:(SNTFileInfo *)fi {
|
||||
if (!fi) return nil;
|
||||
|
||||
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] blacklistPathRegex];
|
||||
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
|
||||
return @"Blacklist Regex";
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/// Copyright 2015 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;
|
||||
|
||||
#import "SNTFileWatcher.h"
|
||||
|
||||
@interface SNTFileWatcherTest : XCTestCase
|
||||
@property NSFileManager *fm;
|
||||
@property NSString *file;
|
||||
@end
|
||||
|
||||
@implementation SNTFileWatcherTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.fm = [NSFileManager defaultManager];
|
||||
self.file = [NSTemporaryDirectory() stringByAppendingString:@"SNTFileWatcherTest_File"];
|
||||
[self createFile];
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[self deleteFile];
|
||||
usleep(10000);
|
||||
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)createFile {
|
||||
[self.fm createFileAtPath:self.file contents:nil attributes:nil];
|
||||
}
|
||||
|
||||
- (void)deleteFile {
|
||||
[self.fm removeItemAtPath:self.file error:NULL];
|
||||
}
|
||||
|
||||
- (void)testPlainInit {
|
||||
XCTAssertThrows([[SNTFileWatcher alloc] init]);
|
||||
}
|
||||
|
||||
- (void)testInitFileExists {
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
[exp fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testInitNewFile {
|
||||
[self deleteFile];
|
||||
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
[exp fulfill];
|
||||
}];
|
||||
|
||||
[self createFile];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileChanged {
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Changed: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if (!fulfilled && [d isEqual:@"0x8BADF00D"]) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
sleep(1);
|
||||
|
||||
[[@"0x8BADF00D" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:NO];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileReplaced {
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Replaced: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if (!fulfilled && [d isEqual:@"0xFACEFEED"]) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
[[@"0xFACEFEED" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:YES];
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileExtended {
|
||||
int fd = open(self.file.fileSystemRepresentation, O_WRONLY);
|
||||
write(fd, "0xDEAD", 6);
|
||||
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Extended: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
int file = open(self.file.fileSystemRepresentation, O_RDONLY);
|
||||
char fileData[10];
|
||||
read(file, fileData, 10);
|
||||
|
||||
if (!fulfilled && strncmp(fileData, "0xDEADBEEF", 10) == 0) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
write(fd, "BEEF", 4);
|
||||
close(fd);
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user