Compare commits

...

38 Commits
0.9.2 ... 0.9.6

Author SHA1 Message Date
Russell Hancox
b4b1fbb9e6 santad: Run watchdog thread loop once before sleeping 2015-10-31 14:01:44 -04:00
Russell Hancox
209eaff3c6 SNTFileInfo: Embed SHA hashing loop in an autoreleasepool to avoid temporary RAM spikes 2015-10-31 13:45:47 -04:00
Russell Hancox
c3f70703fd santactl/status: Expose peak CPU/RAM use from santad. 2015-10-29 16:20:57 -04:00
Russell Hancox
f2967e7b94 santad: Switch watchdog CPU counter from rusage to task_info, capture peak CPU/RAM use. 2015-10-29 16:20:25 -04:00
Russell Hancox
77c46b5c43 SNTFileInfo: switch from NSData to NSFileHandle.
This seems to work much better than NSData with either mapped (SIGBUS when file is deleted) or uncached (ballooning memory use) reading.
2015-10-29 16:17:12 -04:00
Russell Hancox
5fda5bc081 santactl/binaryinfo: Only print bundle lines if bundle info is present 2015-10-29 12:35:27 -04:00
Russell Hancox
33a7b38c6a SNTFileInfo: check for NULL ptrs when parsing for embedded plist 2015-10-27 18:35:11 -04:00
Russell Hancox
2a7c0bd58c SNTFileInfo: Go back to using mmap, uncached read balloons memory use 2015-10-27 18:08:16 -04:00
Russell Hancox
86e4d0db0f santactl: Use yyyy instead of YYYY in NSDateFormatter 2015-10-27 17:58:23 -04:00
Russell Hancox
1310fea64d santa-driver: Only try to use/release proc_t if proc_find found it. 2015-10-22 11:29:49 -04:00
Russell Hancox
382f5a5bb9 Merge pull request #30 from stephanemoore/patch-1
Fix application deadlock.
2015-10-22 08:39:54 -04:00
Stephane Moore
ff3303e312 Fix application deadlock.
Fix application deadlock by asynchronously dispatching to the main queue in -[SNTAppDelegate createConnection].
2015-10-21 17:45:59 -07:00
Russell Hancox
6ce0ef62e9 SantaGUI: Ensure connection is only made on main thread 2015-10-15 18:31:07 -04:00
Russell Hancox
2a03341fb6 santad: Add configuration option for turning off PAGEZERO protection. 2015-10-15 18:10:00 -04:00
Russell Hancox
77a55dde56 santad: Catch errors archiving/unarchiving SNTStoredEvent, delete events that fail 2015-10-15 18:09:46 -04:00
Russell Hancox
1a71cdff4a santad/santactl: Report back if rule adding/removing failed rather than assuming success. 2015-10-15 12:15:38 -04:00
Russell Hancox
63f65c51c3 SNTFileInfo: Use NSURL method for getting quarantine data, don't try to use <10.10 2015-10-15 12:14:53 -04:00
Russell Hancox
75de2526c1 santactl/binaryinfo: Only print quarantine fields if they're not empty 2015-10-14 23:37:16 -04:00
Russell Hancox
6fc4b7b120 santactl/binaryinfo: Increase key padding +1 2015-10-14 23:31:50 -04:00
Russell Hancox
7b8068139b santad, santactl/sync: Collect and upload quarantine data with events. 2015-10-14 23:02:20 -04:00
Russell Hancox
ced7de884f santactl/binaryinfo: Add quarantine data to output, add print method to simplify changes. 2015-10-14 20:12:04 -04:00
Russell Hancox
bc51c9f25b SNTFileInfo: Add com.apple.quarantine data accessors for downloaded files. 2015-10-14 20:11:32 -04:00
Russell Hancox
c412e8b9a7 SNTFileInfo: Fix embedded plist parsing, extract into separate method 2015-10-14 20:07:50 -04:00
Russell Hancox
4e0ff224b6 Project: Remove SNTCertificate/SNTCodesignChecker, use new CocoaPod versions 2015-10-12 17:23:42 -04:00
Russell Hancox
61c817c9cb Tests: Fix SNTRuleTable tests 2015-10-09 15:14:15 -04:00
Russell Hancox
2ed384f677 santactl/sync: Only update client mode at end of sync 2015-10-09 13:12:25 -04:00
Russell Hancox
7a851cb080 santad: Typo in comment 2015-10-08 19:54:23 -04:00
Russell Hancox
13aa889633 SNTFileInfo: Add fileSize method, use it in SNTEventLog 2015-10-08 17:57:02 -04:00
Russell Hancox
5c3fba5f41 santad: Prevent user/server from accidentally deleting rules that would kill the system. 2015-10-08 17:45:39 -04:00
Russell Hancox
145d9216bf Project: Don't bother with "xcodebuild clean" for Rakefile clean rule 2015-10-08 17:43:59 -04:00
Russell Hancox
84f46de940 Driver/Daemon: Collect process name in-kernel for file events, parent name for exec requests. For file events log process name and path, if possible. 2015-10-05 17:09:33 -04:00
Russell Hancox
cb9a5b6fbe santactl: Add --json option to both status and version commands. 2015-10-05 14:15:10 -04:00
Russell Hancox
d9718faba4 SNTFileInfo: Return non-embedded dict if locating embedded fails 2015-10-05 14:13:40 -04:00
Russell Hancox
5472ff41f0 santactl/status: Show timezone as UTF offset rather than name 2015-10-05 13:00:55 -04:00
Russell Hancox
4f94c3b310 santactl/status: Use fixed format for sync date output but still include TZ. 2015-10-03 19:57:19 -04:00
Russell Hancox
420f1efa50 santad: For file write events, print process name as well as pid. 2015-10-03 18:16:06 -04:00
Russell Hancox
5d2ce17817 santactl/status: When printing last sync date, use local timezone and locale settings 2015-10-03 18:15:41 -04:00
Russell Hancox
053cb823a1 santa-driver: Change C++ std to C++11
This is mostly just to quiet the warning about override not being set on getMetaClass, which is part of the OSDeclareDefaultStructors macro.
2015-10-03 18:15:11 -04:00
50 changed files with 779 additions and 1487 deletions

16
Podfile
View File

@@ -2,7 +2,19 @@ platform :osx, "10.9"
inhibit_all_warnings!
target :santactl do
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
end
target :Santa do
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
end
target :santad do
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'FMDB'
post_install do |installer|
@@ -20,6 +32,8 @@ target :santad do
end
target :LogicTests do
pod 'OCMock'
pod 'FMDB'
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'OCMock'
end

View File

@@ -4,14 +4,21 @@ PODS:
- FMDB/common (2.5)
- FMDB/standard (2.5):
- FMDB/common
- OCMock (3.1.2)
- MOLCertificate (1.1)
- MOLCodesignChecker (1.2):
- MOLCertificate (~> 1.1)
- OCMock (3.2)
DEPENDENCIES:
- FMDB
- MOLCertificate
- MOLCodesignChecker
- OCMock
SPEC CHECKSUMS:
FMDB: 96e8f1bcc1329e269330f99770ad4285d9003e52
OCMock: a10ea9f0a6e921651f96f78b6faee95ebc813b92
MOLCertificate: 57fb88b33e83008d45c75644937fca61ed9f63d3
MOLCodesignChecker: e887eeeb7cd87c9b808d1682187c8a27f8ff1100
OCMock: 28def049ef47f996b515a8eeea958be7ccab2dbb
COCOAPODS: 0.38.2
COCOAPODS: 0.39.0

View File

@@ -44,7 +44,6 @@ end
desc "Clean"
task :clean => :init do
puts "Cleaning"
xcodebuild("-scheme All clean")
FileUtils.rm_rf(OUTPUT_PATH)
FileUtils.rm_rf(DIST_PATH)
end

View File

@@ -26,6 +26,7 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
02D7203A6CEE2A946FB08ECE /* libPods-santactl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A2EA300312100AE62218F84E /* libPods-santactl.a */; };
0D0016A3192BCD3C005E7FCD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9A7F3E1759330500035EB5 /* Foundation.framework */; };
0D0016A6192BCD3C005E7FCD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0016A5192BCD3C005E7FCD /* main.m */; };
0D0016AE192BCD8C005E7FCD /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
@@ -36,21 +37,16 @@
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */; };
0D10BE8B1A0AB23300C0C944 /* SNTDERDecoderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10BE8A1A0AB23300C0C944 /* SNTDERDecoderTest.m */; };
0D10BE8C1A0AB3FD00C0C944 /* SNTDERDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7FFD4A1A017D4B00F34435 /* SNTDERDecoder.m */; };
0D1AF477187C7A2C00D3298D /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
0D1AF478187C7A2C00D3298D /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */; };
0D1B477119A53419008CADD3 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D1B476F19A53419008CADD3 /* AboutWindow.xib */; };
0D20710E1A7C4A86008B0A9A /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
0D2CD4611A81C7B100C9C910 /* dn.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0D2CD4601A81C7B100C9C910 /* dn.plist */; };
0D31DF4718D254B3002B300D /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
0D35BD9F18FD71CE00921A21 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9A7F3E1759330500035EB5 /* Foundation.framework */; };
0D35BDA218FD71CE00921A21 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDA118FD71CE00921A21 /* main.m */; };
0D35BDAC18FD7CFD00921A21 /* SNTCommandController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */; };
0D35BDB518FD84F600921A21 /* SNTCommandSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDB418FD84F600921A21 /* SNTCommandSync.m */; };
0D35BDBD18FDA23600921A21 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
0D35BDC018FDA5C800921A21 /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
0D35BDC218FDA5D100921A21 /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
0D35BDC418FDA5D100921A21 /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D377C2A17A071B7008453DB /* SNTEventTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D377C2917A071B7008453DB /* SNTEventTable.m */; };
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D37C10E18F6029A0069BC61 /* SNTDatabaseTable.m */; };
@@ -83,7 +79,6 @@
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D536EDC1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D54E0B11976F8D3000BB59F /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
0D59C0E417710E6000748EBF /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D668E8018D1121700E29A8B /* SNTMessageWindow.m */; };
@@ -92,7 +87,6 @@
0D6FDC8318C68D7E0044685C /* GIAG2.crt in Resources */ = {isa = PBXBuildFile; fileRef = 0D6FDC8218C68D7E0044685C /* GIAG2.crt */; };
0D6FDC8518C68E500044685C /* GIAG2.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0D6FDC8418C68E500044685C /* GIAG2.pem */; };
0D6FDC8718C6913D0044685C /* apple.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0D6FDC8618C6913D0044685C /* apple.pem */; };
0D6FDC8C18C69AF90044685C /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
0D6FDC9618C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D6FDC9718C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D7A7AF3174FCF4C00B77646 /* SantaMessage.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0D7A7AF1174FCF4C00B77646 /* SantaMessage.cc */; };
@@ -141,12 +135,9 @@
0DCD605C19117A90006B445C /* SNTCommandSyncPreflight.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD605B19117A90006B445C /* SNTCommandSyncPreflight.m */; };
0DCD6062191188B1006B445C /* SNTAuthenticatingURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6061191188B1006B445C /* SNTAuthenticatingURLSession.m */; };
0DD0D487194F5187005F27EB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
0DD0D48B194F6193005F27EB /* SNTCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */; };
0DD0D48D194F6D5B005F27EB /* SNTCodesignCheckerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */; };
0DD0D48F194F78F8005F27EB /* SNTFileInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */; };
0DD0D491194F9947005F27EB /* SNTExecutionControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */; };
0DD0D492194F9BEF005F27EB /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
0DD65D98184D2F0A00822DA7 /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
0DE4C8A118FEF28200466D04 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D8C200B180F359A00CE2BF8 /* Security.framework */; };
0DE4C8A618FF3B1700466D04 /* SNTCommandFlushCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */; };
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
@@ -165,6 +156,7 @@
0DF395661AB76ABC00CBC520 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0DF395651AB76ABC00CBC520 /* libz.dylib */; };
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 409232791A51B65D00A04527 /* SNTCommandRule.m */; };
8BFD9B39112F4D16B3D0EFFB /* libPods-LogicTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */; };
CB7CD33A4D1B4745552333F4 /* libPods-Santa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7544A9B819620883181F257 /* libPods-Santa.a */; };
E86AE075D7F24FB88FB627C5 /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A84545E322F475FA0B505D5 /* libPods-santad.a */; };
/* End PBXBuildFile section */
@@ -252,8 +244,6 @@
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDropRootPrivs.m; sourceTree = "<group>"; };
0D10BE881A0AAC2100C0C944 /* SNTDropRootPrivs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTDropRootPrivs.h; sourceTree = "<group>"; };
0D10BE8A1A0AB23300C0C944 /* SNTDERDecoderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDERDecoderTest.m; sourceTree = "<group>"; };
0D1AF475187C7A2C00D3298D /* SNTCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCertificate.h; sourceTree = "<group>"; };
0D1AF476187C7A2C00D3298D /* SNTCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCertificate.m; sourceTree = "<group>"; };
0D1B476D19A53419008CADD3 /* SNTAboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTAboutWindowController.h; sourceTree = "<group>"; };
0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTAboutWindowController.m; sourceTree = "<group>"; };
0D1B476F19A53419008CADD3 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindow.xib; sourceTree = "<group>"; };
@@ -306,8 +296,6 @@
0D536ED61B8E7A2E0039A26D /* missing_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = missing_pagezero; sourceTree = "<group>"; };
0D536ED91B94E9230039A26D /* SNTEventLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
0D536EDA1B94E9230039A26D /* SNTEventLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
0D59C0E217710E6000748EBF /* SNTCodesignChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCodesignChecker.h; sourceTree = "<group>"; };
0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCodesignChecker.m; sourceTree = "<group>"; };
0D63DD5A1906FCB400D346C4 /* SNTDatabaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDatabaseController.h; sourceTree = "<group>"; };
0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDatabaseController.m; sourceTree = "<group>"; };
0D668E7F18D1121700E29A8B /* SNTMessageWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTMessageWindow.h; sourceTree = "<group>"; };
@@ -363,8 +351,6 @@
0DCD605B19117A90006B445C /* SNTCommandSyncPreflight.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncPreflight.m; sourceTree = "<group>"; };
0DCD6060191188B1006B445C /* SNTAuthenticatingURLSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTAuthenticatingURLSession.h; sourceTree = "<group>"; };
0DCD6061191188B1006B445C /* SNTAuthenticatingURLSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTAuthenticatingURLSession.m; sourceTree = "<group>"; };
0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCertificateTest.m; sourceTree = "<group>"; };
0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCodesignCheckerTest.m; sourceTree = "<group>"; };
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileInfoTest.m; sourceTree = "<group>"; };
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTExecutionControllerTest.m; sourceTree = "<group>"; };
0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandFlushCache.m; sourceTree = "<group>"; };
@@ -384,10 +370,16 @@
0DF395651AB76ABC00CBC520 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
13A4FE400F3857C0F5831498 /* Pods-LogicTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LogicTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests.debug.xcconfig"; sourceTree = "<group>"; };
409232791A51B65D00A04527 /* SNTCommandRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SNTCommandRule.m; path = rule/SNTCommandRule.m; sourceTree = "<group>"; };
54DD0E77B8BE005AFB7E944A /* Pods-santactl.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santactl.release.xcconfig"; path = "Pods/Target Support Files/Pods-santactl/Pods-santactl.release.xcconfig"; sourceTree = "<group>"; };
583E60E97931BA83D5273304 /* Pods-santactl.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santactl.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santactl/Pods-santactl.debug.xcconfig"; sourceTree = "<group>"; };
627BB4EC9917DC20E89D718C /* Pods-santad.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santad/Pods-santad.debug.xcconfig"; sourceTree = "<group>"; };
752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LogicTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
8003CA1D3E46447BCEA56440 /* Pods-santad.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.release.xcconfig"; path = "Pods/Target Support Files/Pods-santad/Pods-santad.release.xcconfig"; sourceTree = "<group>"; };
8D738300867507BD7985972F /* Pods-Santa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.release.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.release.xcconfig"; sourceTree = "<group>"; };
A2EA300312100AE62218F84E /* libPods-santactl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santactl.a"; sourceTree = BUILT_PRODUCTS_DIR; };
BE74E23CF5A553E5F02462B9 /* Pods-LogicTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LogicTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests.release.xcconfig"; sourceTree = "<group>"; };
DE1F4E0329B023976A1BAC19 /* Pods-Santa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.debug.xcconfig"; sourceTree = "<group>"; };
E7544A9B819620883181F257 /* libPods-Santa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Santa.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -418,6 +410,7 @@
0DE4C8A118FEF28200466D04 /* Security.framework in Frameworks */,
0D35BDBD18FDA23600921A21 /* IOKit.framework in Frameworks */,
0D35BD9F18FD71CE00921A21 /* Foundation.framework in Frameworks */,
02D7203A6CEE2A946FB08ECE /* libPods-santactl.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -429,6 +422,7 @@
0D6F12D819EC8822006B218E /* SecurityInterface.framework in Frameworks */,
0D8C200C180F359A00CE2BF8 /* Security.framework in Frameworks */,
0D385DB8180DE4A900418BC6 /* Cocoa.framework in Frameworks */,
CB7CD33A4D1B4745552333F4 /* libPods-Santa.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -458,8 +452,6 @@
isa = PBXGroup;
children = (
0D260DB018B68E12002A0B55 /* Resources */,
0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */,
0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */,
0D10BE8A1A0AB23300C0C944 /* SNTDERDecoderTest.m */,
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
@@ -641,6 +633,8 @@
0D385DB7180DE4A900418BC6 /* Cocoa.framework */,
752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */,
0A84545E322F475FA0B505D5 /* libPods-santad.a */,
E7544A9B819620883181F257 /* libPods-Santa.a */,
A2EA300312100AE62218F84E /* libPods-santactl.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -665,10 +659,6 @@
0D91BCD5174E8AAB00131A7D /* common */ = {
isa = PBXGroup;
children = (
0D1AF475187C7A2C00D3298D /* SNTCertificate.h */,
0D1AF476187C7A2C00D3298D /* SNTCertificate.m */,
0D59C0E217710E6000748EBF /* SNTCodesignChecker.h */,
0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */,
0D91BCE4174E8B5E00131A7D /* SNTCommonEnums.h */,
0D42D2B619D2042900955F08 /* SNTConfigurator.h */,
0D42D2B719D2042900955F08 /* SNTConfigurator.m */,
@@ -775,6 +765,10 @@
BE74E23CF5A553E5F02462B9 /* Pods-LogicTests.release.xcconfig */,
627BB4EC9917DC20E89D718C /* Pods-santad.debug.xcconfig */,
8003CA1D3E46447BCEA56440 /* Pods-santad.release.xcconfig */,
DE1F4E0329B023976A1BAC19 /* Pods-Santa.debug.xcconfig */,
8D738300867507BD7985972F /* Pods-Santa.release.xcconfig */,
583E60E97931BA83D5273304 /* Pods-santactl.debug.xcconfig */,
54DD0E77B8BE005AFB7E944A /* Pods-santactl.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@@ -830,6 +824,7 @@
0D260DA918B68E12002A0B55 /* Frameworks */,
0D260DAA18B68E12002A0B55 /* Resources */,
85CE5DF0D54C438A8933A631 /* Copy Pods Resources */,
4B68B2D454C1C55D29AA76D8 /* Embed Pods Frameworks */,
);
buildRules = (
);
@@ -844,9 +839,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 0D35BDA918FD71CE00921A21 /* Build configuration list for PBXNativeTarget "santactl" */;
buildPhases = (
AAFCB010997D370F4297BF35 /* Check Pods Manifest.lock */,
0DD98E671A5DD02000A754C6 /* Update Version Info */,
0D35BD9A18FD71CE00921A21 /* Sources */,
0D35BD9B18FD71CE00921A21 /* Frameworks */,
32AA711FA23052E0F2EE59EB /* Copy Pods Resources */,
);
buildRules = (
);
@@ -861,10 +858,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 0D385DE3180DE4A900418BC6 /* Build configuration list for PBXNativeTarget "Santa" */;
buildPhases = (
4347374E751B0BF8CF6A7110 /* Check Pods Manifest.lock */,
0DD98E681A5DD03E00A754C6 /* Update Version Info */,
0D385DB2180DE4A900418BC6 /* Sources */,
0D385DB3180DE4A900418BC6 /* Frameworks */,
0D385DB4180DE4A900418BC6 /* Resources */,
309C93A0ACB98D32A337D908 /* Embed Pods Frameworks */,
2AB78B9612925DE634AE8F7C /* Copy Pods Resources */,
);
buildRules = (
);
@@ -1073,6 +1073,51 @@
shellPath = /bin/sh;
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nsed -i '' \"s/TO.BE.FILLED/${GIT_TAG}/\" ${DERIVED_FILE_DIR}/santa-driver_info.c";
};
2AB78B9612925DE634AE8F7C /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-resources.sh\"\n";
showEnvVarsInLog = 0;
};
309C93A0ACB98D32A337D908 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
32AA711FA23052E0F2EE59EB /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santactl/Pods-santactl-resources.sh\"\n";
showEnvVarsInLog = 0;
};
34C9C9E8C5454BBE980DF8A9 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1103,6 +1148,36 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santad/Pods-santad-resources.sh\"\n";
showEnvVarsInLog = 0;
};
4347374E751B0BF8CF6A7110 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
4B68B2D454C1C55D29AA76D8 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
85CE5DF0D54C438A8933A631 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1118,6 +1193,21 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
AAFCB010997D370F4297BF35 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
AE05898CB3CE4507B2F43B91 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1165,7 +1255,6 @@
0DEFB7C61ACDE5F600B92AAE /* SNTFileWatcher.m in Sources */,
0D10BE8B1A0AB23300C0C944 /* SNTDERDecoderTest.m in Sources */,
0DEFB7C81ACF0BFE00B92AAE /* SNTFileWatcherTest.m in Sources */,
0DD0D48B194F6193005F27EB /* SNTCertificateTest.m in Sources */,
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */,
0D3AFBE718FB32CB0087BCEE /* SNTXPCConnectionTest.m in Sources */,
0DCD605719115E54006B445C /* SNTDaemonControlController.m in Sources */,
@@ -1173,13 +1262,10 @@
0D3AFBEE18FB4C6C0087BCEE /* SNTApplication.m in Sources */,
0DD0D48F194F78F8005F27EB /* SNTFileInfoTest.m in Sources */,
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */,
0D31DF4718D254B3002B300D /* SNTCodesignChecker.m in Sources */,
0DD0D492194F9BEF005F27EB /* SNTLogging.m in Sources */,
0DE71A761B95F7F900518526 /* SNTCachedDecision.m in Sources */,
0DD0D48D194F6D5B005F27EB /* SNTCodesignCheckerTest.m in Sources */,
0DCD605919115E5A006B445C /* SNTXPCNotifierInterface.m in Sources */,
0DE50F691912B0CD007B2B0C /* SNTRule.m in Sources */,
0D6FDC8C18C69AF90044685C /* SNTCertificate.m in Sources */,
0D10BE8C1A0AB3FD00C0C944 /* SNTDERDecoder.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1189,7 +1275,6 @@
buildActionMask = 2147483647;
files = (
0DA73CA21934F88D0056D7C4 /* SNTLogging.m in Sources */,
0D35BDC218FDA5D100921A21 /* SNTCodesignChecker.m in Sources */,
0D35BDB518FD84F600921A21 /* SNTCommandSync.m in Sources */,
0DCD5FBF1909D64A006B445C /* SNTCommandBinaryInfo.m in Sources */,
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */,
@@ -1210,7 +1295,6 @@
0DCD6043190ACCB8006B445C /* SNTFileInfo.m in Sources */,
0DE50F6E191304E0007B2B0C /* SNTRule.m in Sources */,
0D0A1EC3191998C900B8450F /* SNTCommandSyncRuleDownload.m in Sources */,
0D35BDC018FDA5C800921A21 /* SNTCertificate.m in Sources */,
0DB390991AB1E11400614002 /* SNTCommandVersion.m in Sources */,
0D42D2B519D1D98A00955F08 /* SNTSystemInfo.m in Sources */,
0D827E6719DF3C74006EC811 /* SNTCommandStatus.m in Sources */,
@@ -1232,8 +1316,6 @@
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */,
0D385DF2180DE51600418BC6 /* SNTMessageWindowController.m in Sources */,
0D385DF3180DE51600418BC6 /* SNTNotificationManager.m in Sources */,
0D1AF478187C7A2C00D3298D /* SNTCertificate.m in Sources */,
0DD65D98184D2F0A00822DA7 /* SNTCodesignChecker.m in Sources */,
0D385DC4180DE4A900418BC6 /* main.m in Sources */,
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */,
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */,
@@ -1265,7 +1347,6 @@
0DCD604B19105433006B445C /* SNTStoredEvent.m in Sources */,
0DB8ACC1185662DC00FEF9C7 /* SNTApplication.m in Sources */,
0D9A7F421759330500035EB5 /* main.m in Sources */,
0D1AF477187C7A2C00D3298D /* SNTCertificate.m in Sources */,
0DA73C9F1934F8100056D7C4 /* SNTLogging.m in Sources */,
0DE71A751B95F7F900518526 /* SNTCachedDecision.m in Sources */,
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */,
@@ -1277,7 +1358,6 @@
0D377C2A17A071B7008453DB /* SNTEventTable.m in Sources */,
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */,
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */,
0D59C0E417710E6000748EBF /* SNTCodesignChecker.m in Sources */,
0D42D2B819D2042900955F08 /* SNTConfigurator.m in Sources */,
0DCD605519115D17006B445C /* SNTXPCControlInterface.m in Sources */,
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */,
@@ -1493,6 +1573,7 @@
};
0D35BDA718FD71CE00921A21 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 583E60E97931BA83D5273304 /* Pods-santactl.debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_MODULES = YES;
@@ -1533,6 +1614,7 @@
};
0D35BDA818FD71CE00921A21 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 54DD0E77B8BE005AFB7E944A /* Pods-santactl.release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_MODULES = YES;
@@ -1567,6 +1649,7 @@
};
0D385DE4180DE4A900418BC6 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = DE1F4E0329B023976A1BAC19 /* Pods-Santa.debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@@ -1608,6 +1691,7 @@
};
0D385DE5180DE4A900418BC6 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8D738300867507BD7985972F /* Pods-Santa.release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@@ -1647,7 +1731,10 @@
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
GCC_C_LANGUAGE_STANDARD = c99;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
PROVISIONING_PROFILE = "";
@@ -1667,8 +1754,11 @@
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = c99;
MACOSX_DEPLOYMENT_TARGET = 10.9;
PROVISIONING_PROFILE = "";
RUN_CLANG_STATIC_ANALYZER = YES;

View File

@@ -71,17 +71,19 @@
#pragma mark Connection handling
- (void)createConnection {
__weak __typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
__weak __typeof(self) weakSelf = self;
self.listener = [[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId]
options:NSXPCConnectionPrivileged];
self.listener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
self.listener.exportedObject = self.notificationManager;
self.listener.rejectedHandler = ^{
[weakSelf attemptReconnection];
};
self.listener.invalidationHandler = self.listener.rejectedHandler;
[self.listener resume];
self.listener = [[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId]
options:NSXPCConnectionPrivileged];
self.listener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
self.listener.exportedObject = self.notificationManager;
self.listener.rejectedHandler = ^{
[weakSelf attemptReconnection];
};
self.listener.invalidationHandler = self.listener.rejectedHandler;
[self.listener resume];
});
}
- (void)attemptReconnection {

View File

@@ -16,7 +16,7 @@
#import <SecurityInterface/SFCertificatePanel.h>
#import "SNTCertificate.h"
#import "MOLCertificate.h"
#import "SNTConfigurator.h"
#import "SNTFileInfo.h"
#import "SNTMessageWindow.h"
@@ -67,7 +67,7 @@
- (IBAction)showCertInfo:(id)sender {
// SFCertificatePanel expects an NSArray of SecCertificateRef's
NSMutableArray *certArray = [NSMutableArray arrayWithCapacity:[self.event.signingChain count]];
for (SNTCertificate *cert in self.event.signingChain) {
for (MOLCertificate *cert in self.event.signingChain) {
[certArray addObject:(id)cert.certRef];
}
@@ -109,7 +109,7 @@
}
- (NSString *)publisherInfo {
SNTCertificate *leafCert = [self.event.signingChain firstObject];
MOLCertificate *leafCert = [self.event.signingChain firstObject];
if (leafCert.commonName && leafCert.orgName) {
return [NSString stringWithFormat:@"%@ - %@", leafCert.orgName, leafCert.commonName];

View File

@@ -1,121 +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.
///
/// SNTCertificate wraps a @c SecCertificateRef to provide Objective-C accessors to
/// commonly used certificate data. Accessors cache data for repeated access.
///
@interface SNTCertificate : NSObject<NSSecureCoding>
///
/// Initialize a SNTCertificate object with a valid SecCertificateRef. Designated initializer.
///
/// @param certRef valid SecCertificateRef, which will be retained.
///
- (instancetype)initWithSecCertificateRef:(SecCertificateRef)certRef;
///
/// Initialize a SNTCertificate object with certificate data in DER format.
///
/// @param certData DER-encoded certificate data.
/// @return initialized SNTCertificate or nil if certData is not a DER-encoded certificate.
///
- (instancetype)initWithCertificateDataDER:(NSData *)certData;
///
/// Initialize a SNTCertificate object with certificate data in PEM format.
/// If multiple PEM certificates exist within the string, the first is used.
///
/// @param certData PEM-encoded certificate data.
/// @return initialized SNTCertifcate or nil if certData is not a PEM-encoded certificate.
///
- (instancetype)initWithCertificateDataPEM:(NSString *)certData;
///
/// Returns an array of SNTCertificate's for all of the certificates in @c pemData.
///
/// @param pemData PEM-encoded certificates.
/// @return array of SNTCertificate objects.
///
+ (NSArray *)certificatesFromPEM:(NSString *)pemData;
///
/// Access the underlying certificate ref.
///
@property(readonly, nonatomic) SecCertificateRef certRef;
///
/// SHA-1 hash of the certificate data.
///
@property(readonly, nonatomic) NSString *SHA1;
///
/// SHA-256 hash of the certificate data.
///
@property(readonly, nonatomic) NSString *SHA256;
///
/// Certificate data.
///
@property(readonly, nonatomic) NSData *certData;
///
/// Common Name e.g: "Software Signing"
///
@property(readonly, nonatomic) NSString *commonName;
///
/// Country Name e.g: "US"
///
@property(readonly, nonatomic) NSString *countryName;
///
/// Organizational Name e.g: "Apple Inc."
///
@property(readonly, nonatomic) NSString *orgName;
///
/// Organizational Unit Name e.g: "Apple Software"
///
@property(readonly, nonatomic) NSString *orgUnit;
///
/// Is this cert a CA?
///
@property(readonly, nonatomic) BOOL isCA;
///
/// The cert serial number
///
@property(readonly, nonatomic) NSString *serialNumber;
///
/// Issuer details, same fields as above.
///
@property(readonly, nonatomic) NSString *issuerCommonName;
@property(readonly, nonatomic) NSString *issuerCountryName;
@property(readonly, nonatomic) NSString *issuerOrgName;
@property(readonly, nonatomic) NSString *issuerOrgUnit;
///
/// Validity Not Before
///
@property(readonly, nonatomic) NSDate *validFrom;
///
/// Validity Not After
///
@property(readonly, nonatomic) NSDate *validUntil;
@end

View File

@@ -1,375 +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 "SNTCertificate.h"
#import <CommonCrypto/CommonDigest.h>
#import <Security/Security.h>
@interface SNTCertificate ()
/// A container for cached property values
@property NSMutableDictionary *memoizedData;
@end
@implementation SNTCertificate
static NSString *const kCertDataKey = @"certData";
#pragma mark Init/Dealloc
- (instancetype)initWithSecCertificateRef:(SecCertificateRef)certRef {
self = [super init];
if (self) {
_certRef = certRef;
CFRetain(_certRef);
}
return self;
}
- (instancetype)initWithCertificateDataDER:(NSData *)certData {
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
if (cert) {
// Despite the header file claiming that SecCertificateCreateWithData will return NULL if
// @c certData doesn't contain a valid DER-encoded X509 cert, this isn't always true.
// radar://problem/16124651
// To workaround, check that the certificate serial number can be retrieved. According to
// RFC5280, the serial number field is required.
NSData *ser = CFBridgingRelease(SecCertificateCopySerialNumber(cert, NULL));
if (ser) {
self = [self initWithSecCertificateRef:cert];
} else {
self = nil;
}
CFRelease(cert); // was retained in initWithSecCertificateRef
} else {
self = nil;
}
return self;
}
- (instancetype)initWithCertificateDataPEM:(NSString *)certData {
// Find the PEM and extract the base64-encoded DER data from within
NSScanner *scanner = [NSScanner scannerWithString:certData];
NSString *base64der;
// Locate and parse DER data into |base64der|
[scanner scanUpToString:@"-----BEGIN CERTIFICATE-----" intoString:NULL];
if (!([scanner scanString:@"-----BEGIN CERTIFICATE-----" intoString:NULL] &&
[scanner scanUpToString:@"-----END CERTIFICATE-----" intoString:&base64der] &&
[scanner scanString:@"-----END CERTIFICATE-----" intoString:NULL])) {
return nil;
}
// base64-decode the DER
SecTransformRef transform = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
if (!transform) return nil;
NSData *input = [base64der dataUsingEncoding:NSUTF8StringEncoding];
NSData *output = nil;
if (SecTransformSetAttribute(transform,
kSecTransformInputAttributeName,
(__bridge CFDataRef)input,
NULL)) {
output = CFBridgingRelease(SecTransformExecute(transform, NULL));
}
if (transform) CFRelease(transform);
return [self initWithCertificateDataDER:output];
}
+ (NSArray *)certificatesFromPEM:(NSString *)pemData {
NSScanner *scanner = [NSScanner scannerWithString:pemData];
NSMutableArray *certs = [[NSMutableArray alloc] init];
while (YES) {
NSString *curCert;
[scanner scanUpToString:@"-----BEGIN CERTIFICATE-----" intoString:NULL];
[scanner scanUpToString:@"-----END CERTIFICATE-----" intoString:&curCert];
// If there was no data, break.
if (!curCert) break;
curCert = [curCert stringByAppendingString:@"-----END CERTIFICATE-----"];
SNTCertificate *cert = [[SNTCertificate alloc] initWithCertificateDataPEM:curCert];
// If the data couldn't be turned into a valid SNTCertificate, continue.
if (!cert) continue;
[certs addObject:cert];
}
return certs;
}
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)dealloc {
if (_certRef) CFRelease(_certRef);
}
#pragma mark Equality & description
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[SNTCertificate class]]) return NO;
SNTCertificate *o = other;
return [self.certData isEqual:o.certData];
}
- (NSUInteger)hash {
return [self.certData hash];
}
- (NSString *)description {
return
[NSString stringWithFormat:@"/O=%@/OU=%@/CN=%@", self.orgName, self.orgUnit, self.commonName];
}
#pragma mark NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.certData forKey:kCertDataKey];
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
NSData *certData = [decoder decodeObjectOfClass:[NSData class] forKey:kCertDataKey];
if ([certData length] == 0) return nil;
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
self = [self initWithSecCertificateRef:cert];
if (cert) CFRelease(cert);
return self;
}
#pragma mark Private Accessors
///
/// For a given selector, caches the value that selector would return on subsequent invocations,
/// using the provided block to get the value on the first invocation.
/// Assumes the selector's value will never change.
///
- (id)memoizedSelector:(SEL)selector forBlock:(id (^)(void))block {
NSString *selName = NSStringFromSelector(selector);
if (!self.memoizedData) {
self.memoizedData = [NSMutableDictionary dictionary];
}
if (!self.memoizedData[selName]) {
id val = block();
if (val) {
self.memoizedData[selName] = val;
} else {
self.memoizedData[selName] = [NSNull null];
}
}
// Return the value if there is one, or nil if the value is NSNull
return self.memoizedData[selName] != [NSNull null] ? self.memoizedData[selName] : nil;
}
- (NSDictionary *)allCertificateValues {
return [self memoizedSelector:_cmd forBlock:^id{
return CFBridgingRelease(SecCertificateCopyValues(self.certRef, NULL, NULL));
}];
}
- (NSDictionary *)x509SubjectName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self allCertificateValues][(__bridge NSString *)kSecOIDX509V1SubjectName];
}];
}
- (NSDictionary *)x509IssuerName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self allCertificateValues][(__bridge NSString *)kSecOIDX509V1IssuerName];
}];
}
///
/// Retrieve the value with the specified label from the X509 dictionary provided
///
/// @param desiredLabel The label you want, e.g: kSecOIDOrganizationName.
/// @param dict The dictionary to look in (Subject or Issuer)
/// @return An @c NSString, the value for the specified label.
///
- (NSString *)x509ValueForLabel:(NSString *)desiredLabel fromDictionary:(NSDictionary *)dict {
@try {
NSArray *valArray = dict[(__bridge NSString *)kSecPropertyKeyValue];
for (NSDictionary *curCertVal in valArray) {
NSString *valueLabel = curCertVal[(__bridge NSString *)kSecPropertyKeyLabel];
if ([valueLabel isEqual:desiredLabel]) {
return curCertVal[(__bridge NSString *)kSecPropertyKeyValue];
}
}
return nil;
}
@catch (NSException *e) {
return nil;
}
}
///
/// Retrieve the specified date from the certificate's values and convert from a reference date
/// to an NSDate object.
///
/// @param key The identifier for the date: @c kSecOIDX509V1ValiditityNot{Before,After}
/// @return An @c NSDate representing the date and time the certificate is valid from or expires.
///
- (NSDate *)dateForX509Key:(NSString *)key {
NSDictionary *curCertVal = [self allCertificateValues][key];
NSNumber *value = curCertVal[(__bridge NSString *)kSecPropertyKeyValue];
NSTimeInterval interval = [value doubleValue];
if (interval) {
return [NSDate dateWithTimeIntervalSinceReferenceDate:interval];
}
return nil;
}
#pragma mark Public Accessors
- (NSString *)SHA1 {
return [self memoizedSelector:_cmd forBlock:^id{
NSMutableData *SHA1Buffer = [[NSMutableData alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH];
CC_SHA1([self.certData bytes], (CC_LONG)[self.certData length], [SHA1Buffer mutableBytes]);
const unsigned char *bytes = (const unsigned char *)[SHA1Buffer bytes];
NSMutableString *hexDigest = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
[hexDigest appendFormat:@"%02x", bytes[i]];
}
return hexDigest;
}];
}
- (NSString *)SHA256 {
return [self memoizedSelector:_cmd forBlock:^id{
NSMutableData *SHA256Buffer = [[NSMutableData alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH];
CC_SHA256([self.certData bytes], (CC_LONG)[self.certData length], [SHA256Buffer mutableBytes]);
const unsigned char *bytes = (const unsigned char *)[SHA256Buffer bytes];
NSMutableString *hexDigest = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[hexDigest appendFormat:@"%02x", bytes[i]];
}
return hexDigest;
}];
}
- (NSData *)certData {
return CFBridgingRelease(SecCertificateCopyData(self.certRef));
}
- (NSString *)commonName {
return [self memoizedSelector:_cmd forBlock:^id{
CFStringRef commonName = NULL;
SecCertificateCopyCommonName(self.certRef, &commonName);
return CFBridgingRelease(commonName);
}];
}
- (NSString *)countryName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDCountryName
fromDictionary:[self x509SubjectName]];
}];
}
- (NSString *)orgName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDOrganizationName
fromDictionary:[self x509SubjectName]];
}];
}
- (NSString *)orgUnit {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDOrganizationalUnitName
fromDictionary:[self x509SubjectName]];
}];
}
- (NSDate *)validFrom {
return [self memoizedSelector:_cmd forBlock:^id{
return [self dateForX509Key:(__bridge NSString *)kSecOIDX509V1ValidityNotBefore];
}];
}
- (NSDate *)validUntil {
return [self memoizedSelector:_cmd forBlock:^id{
return [self dateForX509Key:(__bridge NSString *)kSecOIDX509V1ValidityNotAfter];
}];
}
- (NSString *)issuerCommonName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDCommonName
fromDictionary:[self x509IssuerName]];
}];
}
- (NSString *)issuerCountryName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDCountryName
fromDictionary:[self x509IssuerName]];
}];
}
- (NSString *)issuerOrgName {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDOrganizationName
fromDictionary:[self x509IssuerName]];
}];
}
- (NSString *)issuerOrgUnit {
return [self memoizedSelector:_cmd forBlock:^id{
return [self x509ValueForLabel:(__bridge NSString *)kSecOIDOrganizationalUnitName
fromDictionary:[self x509IssuerName]];
}];
}
- (BOOL)isCA {
return [[self memoizedSelector:_cmd forBlock:^id{
NSDictionary *dict = [self allCertificateValues][(__bridge NSString *)kSecOIDBasicConstraints];
return [self x509ValueForLabel:@"Certificate Authority"
fromDictionary:dict];
}] isEqual:@"Yes"];
}
- (NSString *)serialNumber {
return [self memoizedSelector:_cmd forBlock:^id{
NSDictionary *dict = [self allCertificateValues][(__bridge NSString *)kSecOIDX509V1SerialNumber];
return dict[(__bridge NSString *)kSecPropertyKeyValue];
}];
}
@end

View File

@@ -1,90 +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.
@class SNTCertificate;
///
/// SNTCodesignChecker validates a binary (either on-disk or in memory) has been signed
/// and if so allows for pulling out the certificates that were used to sign it.
///
@interface SNTCodesignChecker : NSObject
///
/// The SecStaticCodeRef that this SNTCodesignChecker is working around
///
@property(readonly) SecStaticCodeRef codeRef;
///
/// Returns a dictionary of raw signing information
///
@property(readonly) NSDictionary *signingInformation;
///
/// Returns an array of @c SNTCertificate objects representing the chain that signed this binary.
///
@property(readonly) NSArray *certificates;
///
/// Returns the leaf certificate that this binary was signed with
///
@property(readonly, nonatomic) SNTCertificate *leafCertificate;
///
/// Returns the on-disk path of this binary.
///
@property(readonly, nonatomic) NSString *binaryPath;
///
/// Designated initializer
/// Takes ownership of the codeRef reference.
///
/// @param codeRef a SecStaticCodeRef or SecCodeRef representing a binary.
/// @return an initialized SNTCodesignChecker if the binary is validly signed, nil otherwise.
///
- (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef;
///
/// Convenience initializer for a binary on disk.
///
/// @param binaryPath A binary file on disk
/// @return an initialized SNTCodesignChecker if file is a binary and is signed, nil otherwise.
///
- (instancetype)initWithBinaryPath:(NSString *)binaryPath;
///
/// Convenience initializer for a binary that is running, by its process ID.
///
/// @param PID Id of a running process.
/// @return an initialized SNTCodesignChecker if binary is signed, nil otherwise.
///
- (instancetype)initWithPID:(pid_t)PID;
///
/// Convenience initializer for the currently running process.
///
/// @return an initialized SNTCodesignChecker if current binary is signed, nil otherwise.
///
- (instancetype)initWithSelf;
///
/// Compares the signatures of the binaries represented by this SNTCodesignChecker and
/// @c otherChecker.
///
/// If both binaries are correctly signed and the leaf signatures are identical.
///
/// @return YES if both binaries are signed with the same leaf certificate.
///
- (BOOL)signingInformationMatches:(SNTCodesignChecker *)otherChecker;
@end

View File

@@ -1,193 +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 "SNTCodesignChecker.h"
#import <Security/Security.h>
#import "SNTCertificate.h"
/**
* kStaticSigningFlags are the flags used when validating signatures on disk.
*
* Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
* up validation (see below) but does mean images, plists, etc will not be checked and modifying
* these will not be considered invalid. To ensure any code inside the binary is still checked,
* we check nested code.
*
* Timings with different flags:
* Checking Xcode 5.1.1 bundle:
* kSecCSDefaultFlags: 3.895s
* kSecCSDoNotValidateResources: 0.013s
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
*
* Checking Google Chrome 36.0.1985.143 bundle:
* kSecCSDefaultFlags: 0.529s
* kSecCSDoNotValidateResources: 0.032s
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
*/
static const SecCSFlags kStaticSigningFlags = kSecCSDoNotValidateResources | kSecCSCheckNestedCode;
/**
* kSigningFlags are the flags used when validating signatures for running binaries.
*
* No special flags needed currently.
*/
static const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
@interface SNTCodesignChecker ()
/// Array of @c SNTCertificate's representing the chain of certs this executable was signed with.
@property NSMutableArray *certificates;
@end
@implementation SNTCodesignChecker
#pragma mark Init/dealloc
- (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef {
self = [super init];
if (self) {
// First check the signing is valid
if (CFGetTypeID(codeRef) == SecStaticCodeGetTypeID()) {
if (SecStaticCodeCheckValidity(codeRef, kStaticSigningFlags, NULL) != errSecSuccess) {
return nil;
}
} else if (CFGetTypeID(codeRef) == SecCodeGetTypeID()) {
if (SecCodeCheckValidity((SecCodeRef)codeRef, kSigningFlags, NULL) != errSecSuccess) {
return nil;
}
} else {
return nil;
}
// Get CFDictionary of signing information for binary
OSStatus status = errSecSuccess;
CFDictionaryRef signingDict = NULL;
status = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingDict);
_signingInformation = CFBridgingRelease(signingDict);
if (status != errSecSuccess) return nil;
// Get array of certificates.
NSArray *certs = _signingInformation[(id)kSecCodeInfoCertificates];
if (!certs) return nil;
// Wrap SecCertificateRef objects in SNTCertificate and put in a new NSArray
NSMutableArray *mutableCerts = [[NSMutableArray alloc] initWithCapacity:certs.count];
for (NSUInteger i = 0; i < certs.count; ++i) {
SecCertificateRef certRef = (__bridge SecCertificateRef)certs[i];
SNTCertificate *newCert = [[SNTCertificate alloc] initWithSecCertificateRef:certRef];
[mutableCerts addObject:newCert];
}
_certificates = [mutableCerts copy];
_codeRef = codeRef;
CFRetain(_codeRef);
}
return self;
}
- (instancetype)initWithBinaryPath:(NSString *)binaryPath {
SecStaticCodeRef codeRef = NULL;
// Get SecStaticCodeRef for binary
if (SecStaticCodeCreateWithPath(
(__bridge CFURLRef)[NSURL fileURLWithPath:binaryPath isDirectory:NO],
kSecCSDefaultFlags,
&codeRef) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeRef];
} else {
self = nil;
}
if (codeRef) CFRelease(codeRef);
return self;
}
- (instancetype)initWithPID:(pid_t)PID {
SecCodeRef codeRef = NULL;
NSDictionary *attributes = @{ (__bridge NSString *)kSecGuestAttributePid : @(PID) };
if (SecCodeCopyGuestWithAttributes(
NULL,
(__bridge CFDictionaryRef)attributes,
kSecCSDefaultFlags,
&codeRef) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeRef];
} else {
self = nil;
}
if (codeRef) CFRelease(codeRef);
return self;
}
- (instancetype)initWithSelf {
SecCodeRef codeSelf = NULL;
if (SecCodeCopySelf(kSecCSDefaultFlags, &codeSelf) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeSelf];
} else {
self = nil;
}
if (codeSelf) CFRelease(codeSelf);
return self;
}
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)dealloc {
if (_codeRef) {
CFRelease(_codeRef);
_codeRef = NULL;
}
}
#pragma mark Description
- (NSString *)description {
NSString *binarySource;
if (CFGetTypeID(self.codeRef) == SecStaticCodeGetTypeID()) {
binarySource = @"On-disk";
} else {
binarySource = @"In-memory";
}
return [NSString stringWithFormat:@"%@ binary, signed by %@, located at: %@",
binarySource, self.leafCertificate.orgName, self.binaryPath];
}
#pragma mark Public accessors
- (SNTCertificate *)leafCertificate {
return [self.certificates firstObject];
}
- (NSString *)binaryPath {
CFURLRef path;
OSStatus status = SecCodeCopyPath(self.codeRef, kSecCSDefaultFlags, &path);
NSURL *pathURL = CFBridgingRelease(path);
if (status != errSecSuccess) return nil;
return [pathURL path];
}
- (BOOL)signingInformationMatches:(SNTCodesignChecker *)otherChecker {
return [self.certificates isEqual:otherChecker.certificates];
}
@end

View File

@@ -57,6 +57,13 @@ extern NSString * const kDefaultConfigFilePath;
///
@property(nonatomic) NSRegularExpression *blacklistPathRegex;
///
/// Enable __PAGEZERO protection, defaults to YES
/// If this flag is set to NO, 32-bit binaries that are missing
/// the __PAGEZERO segment will not be blocked.
///
@property(readonly, nonatomic) BOOL enablePageZeroProtection;
#pragma mark - GUI Settings
///

View File

@@ -40,6 +40,7 @@ static NSString * const kClientModeKey = @"ClientMode";
static NSString * const kFileChangesRegexKey = @"FileChangesRegex";
static NSString * const kWhitelistRegexKey = @"WhitelistRegex";
static NSString * const kBlacklistRegexKey = @"BlacklistRegex";
static NSString * const kEnablePageZeroProtectionKey = @"EnablePageZeroProtection";
static NSString * const kMoreInfoURLKey = @"MoreInfoURL";
static NSString * const kEventDetailURLKey = @"EventDetailURL";
@@ -174,6 +175,11 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
[self saveConfigToDisk];
}
- (BOOL)enablePageZeroProtection {
NSNumber *keyValue = self.configData[kEnablePageZeroProtectionKey];
return keyValue ? [keyValue boolValue] : YES;
}
- (NSURL *)moreInfoURL {
return [NSURL URLWithString:self.configData[kMoreInfoURLKey]];
}

View File

@@ -109,8 +109,8 @@
///
/// @return Either the Info.plist in the bundle this file is part of, or an embedded plist if there
/// is one. In the odd case that a file has both an embedded Info.plist and is part of a bundle,
/// the Info.plist from the bundle will be returned.
/// is one. In the unlikely event that a file has both an embedded Info.plist and is part of a
/// bundle, the embedded plist will be returned.
///
- (NSDictionary *)infoPlist;
@@ -135,9 +135,28 @@
- (NSString *)bundleShortVersionString;
///
/// @return any URLs this file may have been downloaded from, using the
/// @c com.apple.metadata:kMDItemWhereFroms extended attribute.
/// @return LaunchServices quarantine data - download URL as an absolute string.
///
- (NSArray *)downloadURLs;
- (NSString *)quarantineDataURL;
///
/// @return LaunchServices quarantine data - referer URL as an absolute string.
///
- (NSString *)quarantineRefererURL;
///
/// @return LaunchServices quarantine data - agent bundle ID.
///
- (NSString *)quarantineAgentBundleID;
///
/// @return LaunchServices quarantine data - timestamp.
///
- (NSDate *)quarantineTimestamp;
///
/// @return The size of the file in bytes.
///
- (NSUInteger)fileSize;
@end

View File

@@ -18,7 +18,7 @@
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <sys/xattr.h>
#include <sys/stat.h>
// Simple class to hold the data of a mach_header and the offset within the file
// in which that header was found.
@@ -40,18 +40,20 @@
@interface SNTFileInfo ()
@property NSString *path;
@property NSData *fileData;
// Dictionary of MachHeaderWithOffset objects where the keys are the architecture strings
@property NSDictionary *machHeaders;
@property NSFileHandle *fileHandle;
@property NSUInteger fileSize;
// Cached properties
@property NSBundle *bundleRef;
@property NSDictionary *infoDict;
@property NSDictionary *quarantineDict;
@property NSDictionary *cachedHeaders;
@end
@implementation SNTFileInfo
extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
- (instancetype)initWithPath:(NSString *)path error:(NSError **)error {
self = [super init];
if (self) {
@@ -67,11 +69,13 @@
return nil;
}
_fileData = [NSData dataWithContentsOfFile:_path
options:NSDataReadingUncached
error:error];
if (_fileData.length == 0) return nil;
[self parseMachHeaders];
_fileHandle = [NSFileHandle fileHandleForReadingAtPath:_path];
struct stat fileStat;
fstat(_fileHandle.fileDescriptor, &fileStat);
_fileSize = fileStat.st_size;
if (_fileSize == 0) return nil;
}
return self;
@@ -82,10 +86,31 @@
}
- (NSString *)SHA1 {
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(self.fileData.bytes, (unsigned int)self.fileData.length, sha1);
const int chunkSize = 4096;
CC_SHA1_CTX c;
CC_SHA1_Init(&c);
for (uint64_t offset = 0; offset < self.fileSize; offset += chunkSize) {
@autoreleasepool {
int readSize;
if (offset + chunkSize > self.fileSize) {
readSize = (int)(self.fileSize - offset);
} else {
readSize = chunkSize;
}
NSData *chunk = [self safeSubdataWithRange:NSMakeRange(offset, readSize)];
if (!chunk) {
CC_SHA1_Final(NULL, &c);
return nil;
}
CC_SHA1_Update(&c, chunk.bytes, readSize);
}
}
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_Final(sha1, &c);
// Convert the binary SHA into hex
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
[buf appendFormat:@"%02x", (unsigned char)sha1[i]];
@@ -95,23 +120,45 @@
}
- (NSString *)SHA256 {
const int chunkSize = 4096;
CC_SHA256_CTX c;
CC_SHA256_Init(&c);
for (uint64_t offset = 0; offset < self.fileSize; offset += chunkSize) {
@autoreleasepool {
int readSize;
if (offset + chunkSize > self.fileSize) {
readSize = (int)(self.fileSize - offset);
} else {
readSize = chunkSize;
}
NSData *chunk = [self safeSubdataWithRange:NSMakeRange(offset, readSize)];
if (!chunk) {
CC_SHA256_Final(NULL, &c);
return nil;
}
CC_SHA256_Update(&c, chunk.bytes, readSize);
}
}
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha256);
CC_SHA256_Final(sha256, &c);
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[buf appendFormat:@"%02x", (unsigned char)sha256[i]];
}
return buf;
}
- (NSString *)machoType {
if ([self isScript]) return @"Script";
if ([self isDylib]) return @"Dynamic Library";
if ([self isKext]) return @"Kernel Extension";
if ([self isFat]) return @"Fat Binary";
if ([self isMachO]) return @"Thin Binary";
if ([self isScript]) return @"Script";
return @"Unknown (not executable?)";
}
@@ -132,11 +179,11 @@
}
- (BOOL)isMachO {
return ([self.machHeaders count] > 0);
return (self.machHeaders.count > 0);
}
- (BOOL)isFat {
return ([self.machHeaders count] > 1);
return (self.machHeaders.count > 1);
}
- (BOOL)isScript {
@@ -146,15 +193,14 @@
- (BOOL)isExecutable {
struct mach_header *mach_header = [self firstMachHeader];
if (!mach_header) return NO;
if (mach_header->filetype == MH_OBJECT || mach_header->filetype == MH_EXECUTE) return YES;
if (mach_header && mach_header->filetype == MH_EXECUTE) return YES;
return NO;
}
- (BOOL)isMissingPageZero {
// This method only checks i386 arch because the kernel enforces this for other archs
// See bsd/kern/mach_loader.c, search for enforce_hard_pagezero.
MachHeaderWithOffset *x86Header = self.machHeaders[@"i386"];
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86]];
if (!x86Header) return NO;
struct mach_header *mh = (struct mach_header *)[x86Header.data bytes];
@@ -224,65 +270,19 @@
- (NSDictionary *)infoPlist {
if (!self.infoDict) {
NSDictionary *d = [self embeddedPlist];
if (d) {
self.infoDict = d;
return self.infoDict;
}
d = self.bundle.infoDictionary;
if (d) {
self.infoDict = d;
return self.infoDict;
}
self.infoDict = (NSDictionary *)[NSNull null];
if (self.bundle) {
NSDictionary *d = self.bundle.infoDictionary;
if (d) self.infoDict = d;
}
// Look for an embedded Info.plist if there is one.
// This could (and used to) use CFBundleCopyInfoDictionaryForURL but that uses mmap to read
// the file and so can cause SIGBUS if the file is deleted/truncated while it's working.
MachHeaderWithOffset *mhwo = [[self.machHeaders allValues] firstObject];
if (!mhwo) return nil;
struct mach_header *mh = (struct mach_header *)mhwo.data.bytes;
if (mh->filetype != MH_EXECUTE) return nil;
BOOL is64 = (mh->magic == MH_MAGIC_64 || mh->magic == MH_CIGAM_64);
uint32_t ncmds = mh->ncmds;
uint32_t nsects = 0;
uint64_t offset = mhwo.offset;
uint32_t sz_header = is64 ? sizeof(struct mach_header_64) : sizeof(struct mach_header);
uint32_t sz_segment = is64 ? sizeof(struct segment_command_64) : sizeof(struct segment_command);
uint32_t sz_section = is64 ? sizeof(struct section_64) : sizeof(struct section);
offset += sz_header;
// Loop through the load commands looking for the segment named __TEXT
for (uint32_t i = 0; i < ncmds; i++) {
NSData *cmdData = [self safeSubdataWithRange:NSMakeRange(offset, sz_segment)];
if (!cmdData) return nil;
struct segment_command_64 *lc = (struct segment_command_64 *)[cmdData bytes];
if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
if (strncmp(lc->segname, "__TEXT", 6) == 0) {
nsects = lc->nsects;
offset += sz_segment;
break;
}
}
offset += lc->cmdsize;
}
// Loop through the sections in the __TEXT segment looking for an __info_plist section.
for (uint32_t i = 0; i < nsects; i++) {
NSData *sectData = [self safeSubdataWithRange:NSMakeRange(offset, sz_section)];
if (!sectData) return nil;
struct section_64 *sect = (struct section_64 *)[sectData bytes];
if (strncmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(sect->offset, sect->size)];
if (!plistData) return nil;
NSDictionary *plist;
plist = [NSPropertyListSerialization propertyListWithData:plistData
options:NSPropertyListImmutable
format:NULL
error:NULL];
if (plist) self.infoDict = plist;
break;
}
offset += sz_section;
}
}
return self.infoDict == (NSDictionary *)[NSNull null] ? nil : self.infoDict;
}
@@ -303,45 +303,41 @@
return [self.infoPlist objectForKey:@"CFBundleShortVersionString"];
}
- (NSArray *)downloadURLs {
char *path = (char *)[self.path fileSystemRepresentation];
size_t size = (size_t)getxattr(path, "com.apple.metadata:kMDItemWhereFroms", NULL, 0, 0, 0);
char *value = malloc(size);
if (!value) return nil;
#pragma mark Quarantine Data
if (getxattr(path, "com.apple.metadata:kMDItemWhereFroms", value, size, 0, 0) == -1) {
free(value);
return nil;
}
- (NSString *)quarantineDataURL {
NSURL *url = [self quarantineData][(__bridge NSString *)kLSQuarantineDataURLKey];
return [url absoluteString];
}
NSData *data = [NSData dataWithBytes:value length:size];
free(value);
- (NSString *)quarantineRefererURL {
NSURL *url = [self quarantineData][(__bridge NSString *)kLSQuarantineOriginURLKey];
return [url absoluteString];
}
if (data) {
NSArray *urls = [NSPropertyListSerialization propertyListWithData:data
options:NSPropertyListImmutable
format:NULL
error:NULL];
return urls;
}
- (NSString *)quarantineAgentBundleID {
return [self quarantineData][(__bridge NSString *)kLSQuarantineAgentBundleIdentifierKey];
}
return nil;
- (NSDate *)quarantineTimestamp {
return [self quarantineData][(__bridge NSString *)kLSQuarantineTimeStampKey];
}
#pragma mark Internal Methods
- (void)parseMachHeaders {
if (self.machHeaders) return;
- (NSDictionary *)machHeaders {
if (self.cachedHeaders) return self.cachedHeaders;
// Sanity check file length
if (self.fileData.length < sizeof(struct mach_header)) {
self.machHeaders = [NSDictionary dictionary];
return;
if (self.fileSize < sizeof(struct mach_header)) {
self.cachedHeaders = [NSDictionary dictionary];
return self.cachedHeaders;
}
NSMutableDictionary *machHeaders = [NSMutableDictionary dictionary];
NSData *machHeader = [self parseSingleMachHeader:self.fileData];
NSData *machHeader = [self parseSingleMachHeader:[self safeSubdataWithRange:NSMakeRange(0,
4096)]];
if (machHeader) {
struct mach_header *mh = (struct mach_header *)[machHeader bytes];
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader offset:0];
@@ -375,7 +371,8 @@
}
}
self.machHeaders = [machHeaders copy];
self.cachedHeaders = [machHeaders copy];
return self.cachedHeaders;
}
- (NSData *)parseSingleMachHeader:(NSData *)inputData {
@@ -396,26 +393,100 @@
}
///
/// Return one of the mach_header's in this file.
/// Locate an embedded plist in the file
///
- (struct mach_header *)firstMachHeader {
return (struct mach_header *)([[[[self.machHeaders allValues] firstObject] data] bytes]);
- (NSDictionary *)embeddedPlist {
// Look for an embedded Info.plist if there is one.
// This could (and used to) use CFBundleCopyInfoDictionaryForURL but that uses mmap to read
// the file and so can cause SIGBUS if the file is deleted/truncated while it's working.
MachHeaderWithOffset *mhwo = [[self.machHeaders allValues] firstObject];
if (!mhwo) return nil;
struct mach_header *mh = (struct mach_header *)mhwo.data.bytes;
if (mh->filetype != MH_EXECUTE) return self.infoDict;
BOOL is64 = (mh->magic == MH_MAGIC_64 || mh->magic == MH_CIGAM_64);
uint32_t ncmds = mh->ncmds;
uint32_t nsects = 0;
uint64_t offset = mhwo.offset;
uint32_t sz_header = is64 ? sizeof(struct mach_header_64) : sizeof(struct mach_header);
uint32_t sz_segment = is64 ? sizeof(struct segment_command_64) : sizeof(struct segment_command);
uint32_t sz_section = is64 ? sizeof(struct section_64) : sizeof(struct section);
offset += sz_header;
// Loop through the load commands looking for the segment named __TEXT
for (uint32_t i = 0; i < ncmds; i++) {
NSData *cmdData = [self safeSubdataWithRange:NSMakeRange(offset, sz_segment)];
if (!cmdData) return nil;
struct segment_command_64 *lc = (struct segment_command_64 *)[cmdData bytes];
if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
if (strncmp(lc->segname, "__TEXT", 6) == 0) {
nsects = lc->nsects;
offset += sz_segment;
break;
}
}
offset += lc->cmdsize;
}
// Loop through the sections in the __TEXT segment looking for an __info_plist section.
for (uint32_t i = 0; i < nsects; i++) {
NSData *sectData = [self safeSubdataWithRange:NSMakeRange(offset, sz_section)];
if (!sectData) return nil;
struct section_64 *sect = (struct section_64 *)[sectData bytes];
if (sect && strncmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(sect->offset, sect->size)];
if (!plistData) return nil;
NSDictionary *plist;
plist = [NSPropertyListSerialization propertyListWithData:plistData
options:NSPropertyListImmutable
format:NULL
error:NULL];
if (plist) return plist;
}
offset += sz_section;
}
return nil;
}
///
/// Wrap @c subdataWithRange: in a @@try/@@catch, returning nil on exception.
/// Useful for when the range is beyond the end of the file.
/// Return the first mach_header in this file.
///
- (struct mach_header *)firstMachHeader {
return (struct mach_header *)([[[[self.machHeaders allValues] firstObject] data] bytes]);
}
///
/// Extract a range of the file as an NSData, handling any exceptions.
/// Returns nil if the requested range is outside of the range of the file.
///
- (NSData *)safeSubdataWithRange:(NSRange)range {
@try {
return [self.fileData subdataWithRange:range];
if ((range.location + range.length) > self.fileSize) return nil;
[self.fileHandle seekToFileOffset:range.location];
NSData *d = [self.fileHandle readDataOfLength:range.length];
if (d.length != range.length) return nil;
return d;
}
@catch (NSException *e) {
return nil;
}
}
///
/// Retrieve quarantine data for a file and caches the dictionary
///
- (NSDictionary *)quarantineData {
if (!self.quarantineDict && NSURLQuarantinePropertiesKey != NULL) {
NSURL *url = [NSURL fileURLWithPath:self.path];
NSDictionary *d = [url resourceValuesForKeys:@[ NSURLQuarantinePropertiesKey ] error:NULL];
self.quarantineDict = d[NSURLQuarantinePropertiesKey];
if (!self.quarantineDict) self.quarantineDict = (NSDictionary *)[NSNull null];
}
return (self.quarantineDict == (NSDictionary *)[NSNull null]) ? nil : self.quarantineDict;
}
///
/// Return a human-readable string for a cpu_type_t.
///
@@ -435,6 +506,13 @@
return nil;
}
///
/// Resolves a given path:
/// + Follows symlinks
/// + Converts relative paths to absolute
/// + If path is a directory, checks to see if that directory is a bundle and if so
/// returns the path to that bundles CFBundleExecutable.
///
- (NSString *)resolvePath:(NSString *)path {
// Convert to absolute, standardized path
path = [path stringByResolvingSymlinksInPath];

View File

@@ -79,6 +79,11 @@ typedef struct {
pid_t ppid;
char path[MAXPATHLEN];
char newpath[MAXPATHLEN];
// For file events, this is the process name.
// For exec requests, this is the parent process name.
// While process names can technically be 4*MAXPATHLEN, that never
// actually happens, so only take MAXPATHLEN and throw away any excess.
char pname[MAXPATHLEN];
} santa_message_t;
#endif // SANTA__COMMON__KERNELCOMMON_H

View File

@@ -55,7 +55,7 @@
@property NSString *fileBundleVersionString;
///
/// If the executed file was signed, this is an NSArray of SNTCertificate's
/// If the executed file was signed, this is an NSArray of MOLCertificate's
/// representing the signing chain.
///
@property NSArray *signingChain;
@@ -100,4 +100,13 @@
///
@property NSString *parentName;
///
/// Quarantine data about the executed file, if any.
///
@property NSString *quarantineDataURL;
@property NSString *quarantineRefererURL;
@property NSDate *quarantineTimestamp;
@property NSString *quarantineAgentBundleID;
@end

View File

@@ -14,7 +14,7 @@
#import "SNTStoredEvent.h"
#import "SNTCertificate.h"
#import "MOLCertificate.h"
@implementation SNTStoredEvent
@@ -49,6 +49,11 @@
ENCODE(self.loggedInUsers, @"loggedInUsers");
ENCODE(self.currentSessions, @"currentSessions");
ENCODE(self.quarantineDataURL, @"quarantineDataURL");
ENCODE(self.quarantineRefererURL, @"quarantineRefererURL");
ENCODE(self.quarantineTimestamp, @"quarantineTiemstamp");
ENCODE(self.quarantineAgentBundleID, @"quarantineAgentBundleID");
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
@@ -63,7 +68,7 @@
_fileBundleVersion = DECODE(NSString, @"fileBundleVersion");
_fileBundleVersionString = DECODE(NSString, @"fileBundleVersionString");
_signingChain = DECODEARRAY(SNTCertificate, @"signingChain");
_signingChain = DECODEARRAY(MOLCertificate, @"signingChain");
_executingUser = DECODE(NSString, @"executingUser");
_occurrenceDate = DECODE(NSDate, @"occurrenceDate");
@@ -74,6 +79,11 @@
_loggedInUsers = DECODEARRAY(NSString, @"loggedInUsers");
_currentSessions = DECODEARRAY(NSString, @"currentSessions");
_quarantineDataURL = DECODE(NSString, @"quarantineDataURL");
_quarantineRefererURL = DECODE(NSString, @"quarantineRefererURL");
_quarantineTimestamp = DECODE(NSDate, @"quarantineTimestamp");
_quarantineAgentBundleID = DECODE(NSString, @"quarantineAgentBundleID");
}
return self;
}

View File

@@ -14,7 +14,7 @@
#import "SNTXPCConnection.h"
#import "SNTCodesignChecker.h"
#import "MOLCodesignChecker.h"
@protocol XPCConnectionValidityRequest
- (void)isConnectionValidWithBlock:(void (^)(BOOL))block;
@@ -97,8 +97,8 @@
[[connection remoteObjectProxy] isConnectionValidWithBlock:^void(BOOL response) {
pid_t pid = self.currentConnection.processIdentifier;
SNTCodesignChecker *selfCS = [[SNTCodesignChecker alloc] initWithSelf];
SNTCodesignChecker *otherCS = [[SNTCodesignChecker alloc] initWithPID:pid];
MOLCodesignChecker *selfCS = [[MOLCodesignChecker alloc] initWithSelf];
MOLCodesignChecker *otherCS = [[MOLCodesignChecker alloc] initWithPID:pid];
if (response && [otherCS signingInformationMatches:selfCS]) {
[self.currentConnection suspend];
@@ -153,8 +153,8 @@
- (void)isConnectionValidWithBlock:(void (^)(BOOL))block {
pid_t pid = self.currentConnection.processIdentifier;
SNTCodesignChecker *selfCS = [[SNTCodesignChecker alloc] initWithSelf];
SNTCodesignChecker *otherCS = [[SNTCodesignChecker alloc] initWithPID:pid];
MOLCodesignChecker *selfCS = [[MOLCodesignChecker alloc] initWithSelf];
MOLCodesignChecker *otherCS = [[MOLCodesignChecker alloc] initWithPID:pid];
if ([otherCS signingInformationMatches:selfCS]) {
[self.currentConnection suspend];

View File

@@ -32,8 +32,10 @@
/// Database ops
///
- (void)databaseRuleCounts:(void (^)(int64_t binary, int64_t certificate))reply;
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate
reply:(void (^)(BOOL success))reply;
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate
reply:(void (^)(BOOL success))reply;
- (void)databaseEventCount:(void (^)(int64_t count))reply;
- (void)databaseEventForSHA256:(NSString *)sha256 reply:(void (^)(SNTStoredEvent *))reply;
@@ -44,8 +46,7 @@
/// Config ops
///
- (void)clientMode:(void (^)(santa_clientmode_t))reply;
- (void)watchdogCPUEvents:(void (^)(uint64_t))reply;
- (void)watchdogRAMEvents:(void (^)(uint64_t))reply;
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply;
- (void)setClientMode:(santa_clientmode_t)mode reply:(void (^)())reply;
- (void)setNextSyncInterval:(uint64_t)seconds reply:(void (^)())reply;
- (void)setSyncLastSuccess:(NSDate *)date reply:(void (^)())reply;

View File

@@ -47,27 +47,27 @@ void SantaDecisionManager::free() {
if (cached_decisions_lock_) {
lck_rw_free(cached_decisions_lock_, sdm_lock_grp_);
cached_decisions_lock_ = NULL;
cached_decisions_lock_ = nullptr;
}
if (dataqueue_lock_) {
lck_mtx_free(dataqueue_lock_, sdm_lock_grp_);
dataqueue_lock_ = NULL;
dataqueue_lock_ = nullptr;
}
if (sdm_lock_attr_) {
lck_attr_free(sdm_lock_attr_);
sdm_lock_attr_ = NULL;
sdm_lock_attr_ = nullptr;
}
if (sdm_lock_grp_) {
lck_grp_free(sdm_lock_grp_);
sdm_lock_grp_ = NULL;
sdm_lock_grp_ = nullptr;
}
if (sdm_lock_grp_attr_) {
lck_grp_attr_free(sdm_lock_grp_attr_);
sdm_lock_grp_attr_ = NULL;
sdm_lock_grp_attr_ = nullptr;
}
super::free();
@@ -101,7 +101,7 @@ void SantaDecisionManager::DisconnectClient(bool itDied) {
message->action = ACTION_REQUEST_SHUTDOWN;
PostToQueue(message);
delete message;
dataqueue_->setNotificationPort(NULL);
dataqueue_->setNotificationPort(nullptr);
} else {
// If the client died, reset the data queue so when it reconnects
// it doesn't get swamped straight away.
@@ -116,8 +116,11 @@ void SantaDecisionManager::DisconnectClient(bool itDied) {
bool SantaDecisionManager::ClientConnected() {
proc_t p = proc_find(client_pid_);
bool is_exiting = proc_exiting(p);
proc_rele(p);
bool is_exiting = false;
if (p) {
is_exiting = proc_exiting(p);
proc_rele(p);
}
return (client_pid_ > 0 && !is_exiting);
}
@@ -145,10 +148,10 @@ kern_return_t SantaDecisionManager::StartListener() {
kern_return_t SantaDecisionManager::StopListener() {
kauth_unlisten_scope(vnode_listener_);
vnode_listener_ = NULL;
vnode_listener_ = nullptr;
kauth_unlisten_scope(fileop_listener_);
fileop_listener_ = NULL;
fileop_listener_ = nullptr;
// Wait for any active invocations to finish before returning
do {
@@ -197,7 +200,7 @@ void SantaDecisionManager::AddToCache(
void SantaDecisionManager::CacheCheck(const char *identifier) {
lck_rw_lock_shared(cached_decisions_lock_);
bool shouldInvalidate = (cached_decisions_->getObject(identifier) != NULL);
bool shouldInvalidate = (cached_decisions_->getObject(identifier) != nullptr);
if (shouldInvalidate) {
if (!lck_rw_lock_shared_to_exclusive(cached_decisions_lock_)) {
// shared_to_exclusive will return false if a previous reader upgraded
@@ -330,6 +333,7 @@ santa_action_t SantaDecisionManager::FetchDecision(
strlcpy(message->path, path, sizeof(message->path));
message->action = ACTION_REQUEST_CHECKBW;
message->vnode_id = vnode_id;
proc_name(message->ppid, message->pname, sizeof(message->pname));
santa_action_t ret = GetFromDaemon(message, vnode_id_str);
delete message;
return ret;
@@ -427,7 +431,7 @@ void SantaDecisionManager::FileOpCallback(
const kauth_action_t action, const vnode_t vp,
const char *path, const char *new_path) {
if (vp) {
vfs_context_t context = vfs_context_create(NULL);
vfs_context_t context = vfs_context_create(nullptr);
uint64_t vnode_id = GetVnodeIDForVnode(context, vp);
vfs_context_rele(context);
@@ -451,6 +455,7 @@ void SantaDecisionManager::FileOpCallback(
santa_message_t *message = NewMessage();
strlcpy(message->path, path, sizeof(message->path));
if (new_path) strlcpy(message->newpath, new_path, sizeof(message->newpath));
proc_name(message->pid, message->pname, sizeof(message->pname));
switch (action) {
case KAUTH_FILEOP_CLOSE:
@@ -481,9 +486,9 @@ extern "C" int fileop_scope_callback(
SantaDecisionManager *sdm = OSDynamicCast(
SantaDecisionManager, reinterpret_cast<OSObject *>(idata));
vnode_t vp = NULL;
char *path = NULL;
char *new_path = NULL;
vnode_t vp = nullptr;
char *path = nullptr;
char *new_path = nullptr;
switch (action) {
case KAUTH_FILEOP_CLOSE:
@@ -517,7 +522,7 @@ extern "C" int vnode_scope_callback(
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
if (action & KAUTH_VNODE_ACCESS ||
!(action & KAUTH_VNODE_EXECUTE) ||
idata == NULL) {
idata == nullptr) {
return KAUTH_RESULT_DEFER;
}

View File

@@ -222,7 +222,7 @@ class SantaDecisionManager : public OSObject {
/// @param action that was requested
/// @param VFS context
/// @param Vnode being operated on
/// @param Parent Vnode. May be NULL.
/// @param Parent Vnode. May be nullptr.
/// @param Pointer to an errno-style error.
///
extern "C" int vnode_scope_callback(

View File

@@ -27,7 +27,7 @@ bool SantaDriver::start(IOService *provider) {
if (!santaDecisionManager->init() ||
santaDecisionManager->StartListener() != kIOReturnSuccess) {
santaDecisionManager->release();
santaDecisionManager = NULL;
santaDecisionManager = nullptr;
return false;
}
@@ -41,7 +41,7 @@ bool SantaDriver::start(IOService *provider) {
void SantaDriver::stop(IOService *provider) {
santaDecisionManager->StopListener();
santaDecisionManager->release();
santaDecisionManager = NULL;
santaDecisionManager = nullptr;
LOGI("Unloaded.");

View File

@@ -49,8 +49,8 @@ bool SantaDriverClient::start(IOService *provider) {
void SantaDriverClient::stop(IOService *provider) {
super::stop(provider);
myProvider = NULL;
decisionManager = NULL;
myProvider = nullptr;
decisionManager = nullptr;
}
IOReturn SantaDriverClient::clientClose() {
@@ -124,7 +124,7 @@ IOReturn SantaDriverClient::static_allow_binary(
void *reference,
IOExternalMethodArguments *arguments) {
if (!target) return kIOReturnBadArgument;
if (arguments->scalarInput == NULL) return kIOReturnBadArgument;
if (arguments->scalarInput == nullptr) return kIOReturnBadArgument;
return target->allow_binary(
static_cast<const uint64_t>(*arguments->scalarInput));
@@ -143,7 +143,7 @@ IOReturn SantaDriverClient::static_deny_binary(
void *reference,
IOExternalMethodArguments *arguments) {
if (!target) return kIOReturnBadArgument;
if (arguments->scalarInput == NULL) return kIOReturnBadArgument;
if (arguments->scalarInput == nullptr) return kIOReturnBadArgument;
return target->deny_binary(
static_cast<const uint64_t>(*arguments->scalarInput));

View File

@@ -16,8 +16,8 @@
#include "SNTLogging.h"
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import "SNTFileInfo.h"
@interface SNTCommandBinaryInfo : NSObject<SNTCommand>
@@ -59,44 +59,57 @@ REGISTER_COMMAND_NAME(@"binaryinfo")
exit(1);
}
printf("%-19s: %s\n", "Path", [[fileInfo path] UTF8String]);
printf("%-19s: %s\n", "SHA-256", [[fileInfo SHA256] UTF8String]);
printf("%-19s: %s\n", "SHA-1", [[fileInfo SHA1] UTF8String]);
printf("%-19s: %s\n", "Bundle Name", [[fileInfo bundleName] UTF8String]);
printf("%-19s: %s\n", "Bundle Version", [[fileInfo bundleVersion] UTF8String]);
printf("%-19s: %s\n", "Bundle Version Str", [[fileInfo bundleShortVersionString] UTF8String]);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
[self printKey:@"Path" value:fileInfo.path];
[self printKey:@"SHA-256" value:fileInfo.SHA256];
[self printKey:@"SHA-1" value:fileInfo.SHA1];
if (fileInfo.bundlePath) {
[self printKey:@"Bundle Name" value:fileInfo.bundleName];
[self printKey:@"Bundle Version" value:fileInfo.bundleVersion];
[self printKey:@"Bundle Version Str" value:fileInfo.bundleShortVersionString];
}
if (fileInfo.quarantineDataURL) {
[self printKey:@"Download Referer URL" value:fileInfo.quarantineRefererURL];
[self printKey:@"Download URL" value:fileInfo.quarantineDataURL];
[self printKey:@"Download Timestamp"
value:[dateFormatter stringFromDate:fileInfo.quarantineTimestamp]];
[self printKey:@"Download Agent" value:fileInfo.quarantineAgentBundleID];
}
NSArray *archs = [fileInfo architectures];
if (archs) {
printf("%-19s: %s (%s)\n", "Type",
[[fileInfo machoType] UTF8String],
[[archs componentsJoinedByString:@", "] UTF8String]);
NSString *s = [NSString stringWithFormat:@"%@ (%@)",
fileInfo.machoType, [archs componentsJoinedByString:@", "]];
[self printKey:@"Type" value:s];
} else {
printf("%-19s: %s\n", "Type", [[fileInfo machoType] UTF8String]);
[self printKey:@"Type" value:fileInfo.machoType];
}
if ([fileInfo isMissingPageZero]) {
printf("%-19s: %s\n", "Page Zero", "__PAGEZERO segment missing/bad!");
[self printKey:@"Page Zero" value:@"__PAGEZERO segment missing/bad!"];
}
SNTCodesignChecker *csc = [[SNTCodesignChecker alloc] initWithBinaryPath:filePath];
printf("%-19s: %s\n", "Code-signed", (csc) ? "Yes" : "No");
MOLCodesignChecker *csc = [[MOLCodesignChecker alloc] initWithBinaryPath:filePath];
[self printKey:@"Code-signed" value:(csc) ? @"Yes" : @"No"];
if (csc) {
printf("Signing chain:\n");
[csc.certificates enumerateObjectsUsingBlock:^(SNTCertificate *c,
[csc.certificates enumerateObjectsUsingBlock:^(MOLCertificate *c,
unsigned long idx,
BOOL *stop) {
idx++; // index from 1
printf(" %2lu. %-20s: %s\n", idx, "SHA-256", [c.SHA256 UTF8String]);
printf(" %2lu. %-20s: %s\n", idx + 1, "SHA-256", [c.SHA256 UTF8String]);
printf(" %-20s: %s\n", "SHA-1", [c.SHA1 UTF8String]);
printf(" %-20s: %s\n", "Common Name", [c.commonName UTF8String]);
printf(" %-20s: %s\n", "Organization", [c.orgName UTF8String]);
printf(" %-20s: %s\n", "Organizational Unit", [c.orgUnit UTF8String]);
printf(" %-20s: %s\n", "Valid From", [[c.validFrom description] UTF8String]);
printf(" %-20s: %s\n", "Valid Until", [[c.validUntil description] UTF8String]);
printf(" %-20s: %s\n", "Valid From",
[[dateFormatter stringFromDate:c.validFrom] UTF8String]);
printf(" %-20s: %s\n", "Valid Until",
[[dateFormatter stringFromDate:c.validUntil] UTF8String]);
printf("\n");
}];
}
@@ -104,4 +117,8 @@ REGISTER_COMMAND_NAME(@"binaryinfo")
exit(0);
}
+ (void)printKey:(NSString *)key value:(NSString *)value {
printf("%-21s: %s\n", [key UTF8String], [value UTF8String]);
}
@end

View File

@@ -16,8 +16,8 @@
#include "SNTLogging.h"
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import "SNTConfigurator.h"
#import "SNTDropRootPrivs.h"
#import "SNTFileInfo.h"
@@ -125,7 +125,7 @@ REGISTER_COMMAND_NAME(@"rule")
if (newRule.type == RULETYPE_BINARY) {
newRule.shasum = fi.SHA256;
} else if (newRule.type == RULETYPE_CERT) {
SNTCodesignChecker *cs = [[SNTCodesignChecker alloc] initWithBinaryPath:fi.path];
MOLCodesignChecker *cs = [[MOLCodesignChecker alloc] initWithBinaryPath:fi.path];
newRule.shasum = cs.leafCertificate.SHA256;
}
}
@@ -136,13 +136,18 @@ REGISTER_COMMAND_NAME(@"rule")
[self printErrorUsageAndExit:@"Either SHA-256 or path to file must be specified"];
}
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule cleanSlate:NO reply:^{
if (newRule.state == RULESTATE_REMOVE) {
printf("Removed rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule cleanSlate:NO reply:^(BOOL success) {
if (!success) {
printf("Failed to modify rules.");
exit(1);
} else {
printf("Added rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
if (newRule.state == RULESTATE_REMOVE) {
printf("Removed rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
} else {
printf("Added rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
}
exit(0);
}
exit(0);
}];
}

View File

@@ -38,7 +38,8 @@ REGISTER_COMMAND_NAME(@"status")
}
+ (NSString *)longHelpText {
return nil;
return (@"Provides details about Santa while it's running.\n"
@" Use --json to output in JSON format");
}
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
@@ -47,6 +48,7 @@ REGISTER_COMMAND_NAME(@"status")
// Daemon status
__block NSString *clientMode;
__block uint64_t cpuEvents, ramEvents;
__block double cpuPeak, ramPeak;
dispatch_group_enter(group);
[[daemonConn remoteObjectProxy] clientMode:^(santa_clientmode_t cm) {
switch (cm) {
@@ -60,16 +62,16 @@ REGISTER_COMMAND_NAME(@"status")
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[[daemonConn remoteObjectProxy] watchdogCPUEvents:^(uint64_t events) {
cpuEvents = events;
[[daemonConn remoteObjectProxy] watchdogInfo:^(uint64_t wd_cpuEvents, uint64_t wd_ramEvents,
double wd_cpuPeak, double wd_ramPeak) {
cpuEvents = wd_cpuEvents;
cpuPeak = wd_cpuPeak;
ramEvents = wd_ramEvents;
ramPeak = wd_ramPeak;
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[[daemonConn remoteObjectProxy] watchdogRAMEvents:^(uint64_t events) {
ramEvents = events;
dispatch_group_leave(group);
}];
char *fileLogging = ([[SNTConfigurator configurator] fileChangesRegex] ? "Enabled" : "Disabled");
BOOL fileLogging = ([[SNTConfigurator configurator] fileChangesRegex] != nil);
// Kext status
__block int64_t cacheCount = -1;
@@ -95,31 +97,65 @@ REGISTER_COMMAND_NAME(@"status")
// Sync status
NSString *syncURLStr = [[[SNTConfigurator configurator] syncBaseURL] absoluteString];
NSString *lastSyncSuccess = [[[SNTConfigurator configurator] syncLastSuccess] description];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
NSDate *lastSyncSuccess = [[SNTConfigurator configurator] syncLastSuccess];
NSString *lastSyncSuccessStr = [dateFormatter stringFromDate:lastSyncSuccess] ?: @"Never";
BOOL syncCleanReqd = [[SNTConfigurator configurator] syncCleanRequired];
// Wait a maximum of 5s for stats collected from daemon to arrive.
if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5))) {
printf("Failed to retrieve some stats from daemon\n\n");
fprintf(stderr, "Failed to retrieve some stats from daemon\n\n");
}
printf(">>> Daemon Info\n");
printf(" %-22s | %s\n", "Mode", [clientMode UTF8String]);
printf(" %-22s | %s\n", "File Logging", fileLogging);
printf(" %-22s | %lld\n", "Watchdog CPU Events", cpuEvents);
printf(" %-22s | %lld\n", "Watchdog RAM Events", ramEvents);
printf(">>> Kernel Info\n");
printf(" %-22s | %lld\n", "Kernel cache count", cacheCount);
printf(">>> Database Info\n");
printf(" %-22s | %lld\n", "Binary Rules", binaryRuleCount);
printf(" %-22s | %lld\n", "Certificate Rules", certRuleCount);
printf(" %-22s | %lld\n", "Events Pending Upload", eventCount);
if ([arguments containsObject:@"--json"]) {
NSDictionary *stats = @{
@"daemon": @{
@"mode": clientMode,
@"file_logging": @(fileLogging),
@"watchdog_cpu_events": @(cpuEvents),
@"watchdog_ram_events": @(ramEvents),
@"watchdog_cpu_peak": @(cpuPeak),
@"watchdog_ram_peak": @(ramPeak),
},
@"kernel": @{
@"cache_count": @(cacheCount),
},
@"database": @{
@"binary_rules": @(binaryRuleCount),
@"certificate_rules": @(certRuleCount),
@"events_pending_upload": @(eventCount),
},
@"sync": @{
@"server": syncURLStr,
@"clean_required": @(syncCleanReqd),
@"last_successful": lastSyncSuccessStr
},
};
NSData *statsData = [NSJSONSerialization dataWithJSONObject:stats
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *statsStr = [[NSString alloc] initWithData:statsData encoding:NSUTF8StringEncoding];
printf("%s\n", [statsStr UTF8String]);
} else {
printf(">>> Daemon Info\n");
printf(" %-22s | %s\n", "Mode", [clientMode UTF8String]);
printf(" %-22s | %s\n", "File Logging", (fileLogging ? "Yes" : "No"));
printf(" %-22s | %lld (Peak: %.2f%%)\n", "Watchdog CPU Events", cpuEvents, cpuPeak);
printf(" %-22s | %lld (Peak: %.2fMB)\n", "Watchdog RAM Events", ramEvents, ramPeak);
printf(">>> Kernel Info\n");
printf(" %-22s | %lld\n", "Kernel cache count", cacheCount);
printf(">>> Database Info\n");
printf(" %-22s | %lld\n", "Binary Rules", binaryRuleCount);
printf(" %-22s | %lld\n", "Certificate Rules", certRuleCount);
printf(" %-22s | %lld\n", "Events Pending Upload", eventCount);
if (syncURLStr) {
printf(">>> Sync Info\n");
printf(" %-22s | %s\n", "Sync Server", [syncURLStr UTF8String]);
printf(" %-22s | %s\n", "Clean Sync Required", (syncCleanReqd ? "Yes" : "No"));
const char *syncDateStr = (lastSyncSuccess ? [lastSyncSuccess UTF8String] : "Never");
printf(" %-22s | %s\n", "Last Successful Sync", syncDateStr);
if (syncURLStr) {
printf(">>> Sync Info\n");
printf(" %-22s | %s\n", "Sync Server", [syncURLStr UTF8String]);
printf(" %-22s | %s\n", "Clean Sync Required", (syncCleanReqd ? "Yes" : "No"));
printf(" %-22s | %s\n", "Last Successful Sync", [lastSyncSuccessStr UTF8String]);
}
}
exit(0);

View File

@@ -14,7 +14,7 @@
#import "SNTAuthenticatingURLSession.h"
#import "SNTCertificate.h"
#import "MOLCertificate.h"
#import "SNTDERDecoder.h"
#import "SNTLogging.h"
@@ -193,7 +193,7 @@
return;
}
SNTCertificate *clientCert = [[SNTCertificate alloc] initWithSecCertificateRef:certificate];
MOLCertificate *clientCert = [[MOLCertificate alloc] initWithSecCertificateRef:certificate];
CFRelease(certificate);
// Switch identity finding method depending on config
@@ -239,7 +239,7 @@
if (foundIdentity) {
SecCertificateRef certificate = NULL;
err = SecIdentityCopyCertificate(foundIdentity, &certificate);
SNTCertificate *clientCert = [[SNTCertificate alloc] initWithSecCertificateRef:certificate];
MOLCertificate *clientCert = [[MOLCertificate alloc] initWithSecCertificateRef:certificate];
LOGD(@"Client Trust: Valid client identity %@.", clientCert);
NSURLCredential *cred =
[NSURLCredential credentialWithIdentity:foundIdentity
@@ -277,11 +277,11 @@
if (self.serverRootsPemData) {
NSString *pemStrings = [[NSString alloc] initWithData:self.serverRootsPemData
encoding:NSASCIIStringEncoding];
NSArray *certs = [SNTCertificate certificatesFromPEM:pemStrings];
NSArray *certs = [MOLCertificate certificatesFromPEM:pemStrings];
// Make a new array of the SecCertificateRef's from the SNTCertificate's.
// Make a new array of the SecCertificateRef's from the MOLCertificate's.
NSMutableArray *certRefs = [[NSMutableArray alloc] initWithCapacity:certs.count];
for (SNTCertificate *cert in certs) {
for (MOLCertificate *cert in certs) {
[certRefs addObject:(id)cert.certRef];
}
@@ -304,7 +304,7 @@
// Print details about the server's leaf certificate.
SecCertificateRef firstCert = SecTrustGetCertificateAtIndex(serverTrust, 0);
if (firstCert) {
SNTCertificate *cert = [[SNTCertificate alloc] initWithSecCertificateRef:firstCert];
MOLCertificate *cert = [[MOLCertificate alloc] initWithSecCertificateRef:firstCert];
LOGD(@"Server Trust: Server leaf cert: %@", cert);
}

View File

@@ -65,6 +65,10 @@ extern NSString * const kCertOrg;
extern NSString * const kCertOU;
extern NSString * const kCertValidFrom;
extern NSString * const kCertValidUntil;
extern NSString * const kQuarantineDataURL;
extern NSString * const kQuarantineRefererURL;
extern NSString * const kQuarantineTimestamp;
extern NSString * const kQuarantineAgentBundleID;
extern NSString * const kLogUploadField;

View File

@@ -67,6 +67,10 @@ NSString * const kCertOrg = @"org";
NSString * const kCertOU = @"ou";
NSString * const kCertValidFrom = @"valid_from";
NSString * const kCertValidUntil = @"valid_until";
NSString * const kQuarantineDataURL = @"quarantine_data_url";
NSString * const kQuarantineRefererURL = @"quarantine_referer_url";
NSString * const kQuarantineTimestamp = @"quarantine_timestamp";
NSString * const kQuarantineAgentBundleID = @"quarantine_agent_bundle_id";
NSString * const kLogUploadField = @"files";

View File

@@ -17,7 +17,7 @@
#include "SNTLogging.h"
#import "NSData+Zlib.h"
#import "SNTCertificate.h"
#import "MOLCertificate.h"
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTStoredEvent.h"
@@ -174,9 +174,14 @@
ADDKEY(newEvent, kPPID, event.ppid);
ADDKEY(newEvent, kParentName, event.parentName);
ADDKEY(newEvent, kQuarantineDataURL, event.quarantineDataURL);
ADDKEY(newEvent, kQuarantineRefererURL, event.quarantineRefererURL);
ADDKEY(newEvent, kQuarantineTimestamp, @([event.quarantineTimestamp timeIntervalSince1970]));
ADDKEY(newEvent, kQuarantineAgentBundleID, event.quarantineAgentBundleID);
NSMutableArray *signingChain = [NSMutableArray arrayWithCapacity:event.signingChain.count];
for (NSUInteger i = 0; i < event.signingChain.count; i++) {
SNTCertificate *cert = [event.signingChain objectAtIndex:i];
MOLCertificate *cert = [event.signingChain objectAtIndex:i];
NSMutableDictionary *certDict = [NSMutableDictionary dictionary];
ADDKEY(certDict, kCertSHA256, cert.SHA256);

View File

@@ -44,6 +44,10 @@
} else {
NSDictionary *r = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (syncState.newClientMode) {
[[daemonConn remoteObjectProxy] setClientMode:syncState.newClientMode reply:^{}];
}
NSString *backoffInterval = r[kBackoffInterval];
if (backoffInterval) {
[[daemonConn remoteObjectProxy] setNextSyncInterval:[backoffInterval intValue] reply:^{}];

View File

@@ -80,9 +80,9 @@
syncState.uploadLogURL = [NSURL URLWithString:r[kUploadLogsURL]];
if ([r[kClientMode] isEqual:kClientModeMonitor]) {
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_MONITOR reply:^{}];
syncState.newClientMode = CLIENTMODE_MONITOR;
} else if ([r[kClientMode] isEqual:kClientModeLockdown]) {
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_LOCKDOWN reply:^{}];
syncState.newClientMode = CLIENTMODE_LOCKDOWN;
}
if ([r[kWhitelistRegex] isKindOfClass:[NSString class]]) {

View File

@@ -71,6 +71,7 @@
if (!resp) {
LOGE(@"Failed to decode server's response");
handler(NO);
return;
}
NSArray *receivedRules = resp[kRules];
@@ -90,9 +91,14 @@
if (syncState.downloadedRules.count) {
[[daemonConn remoteObjectProxy] databaseRuleAddRules:syncState.downloadedRules
cleanSlate:syncState.cleanSync
reply:^{
LOGI(@"Added %lu rule(s)", syncState.downloadedRules.count);
handler(YES);
reply:^(BOOL success) {
if (success) {
LOGI(@"Added %lu rule(s)", syncState.downloadedRules.count);
handler(YES);
} else {
LOGE(@"Failed to add rules to database");
handler(NO);
}
}];
} else {
handler(YES);

View File

@@ -12,6 +12,8 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
#include "SNTCommonEnums.h"
/// An instance of this class is passed to each stage of the sync process for storing data
/// that might be needed in later stages.
@interface SNTCommandSyncState : NSObject
@@ -27,6 +29,9 @@
/// should be deleted before inserting any new rules.
@property BOOL cleanSync;
/// New client mode sent from server
@property santa_clientmode_t newClientMode;
/// Batch size for uploading events, sent from server
@property int32_t eventBatchSize;

View File

@@ -41,14 +41,30 @@ REGISTER_COMMAND_NAME(@"version")
}
+ (NSString *)longHelpText {
return nil;
return (@"Show versions of all Santa components.\n"
@" Use --json to output in JSON format.");
}
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
printf("%-15s | %s\n", "santa-driver", [[self santaKextVersion] UTF8String]);
printf("%-15s | %s\n", "santad", [[self santadVersion] UTF8String]);
printf("%-15s | %s\n", "santactl", [[self santactlVersion] UTF8String]);
printf("%-15s | %s\n", "SantaGUI", [[self santaAppVersion] UTF8String]);
if ([arguments containsObject:@"--json"]) {
NSDictionary *versions = @{
@"santa-driver": [self santaKextVersion],
@"santad": [self santadVersion],
@"santactl": [self santactlVersion],
@"SantaGUI": [self santaAppVersion],
};
NSData *versionsData = [NSJSONSerialization dataWithJSONObject:versions
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *versionsStr = [[NSString alloc] initWithData:versionsData
encoding:NSUTF8StringEncoding];
printf("%s\n", [versionsStr UTF8String]);
} else {
printf("%-15s | %s\n", "santa-driver", [[self santaKextVersion] UTF8String]);
printf("%-15s | %s\n", "santad", [[self santadVersion] UTF8String]);
printf("%-15s | %s\n", "santactl", [[self santactlVersion] UTF8String]);
printf("%-15s | %s\n", "SantaGUI", [[self santaAppVersion] UTF8String]);
}
exit(0);
}
@@ -58,7 +74,7 @@ REGISTER_COMMAND_NAME(@"version")
(__bridge CFArrayRef)@[ @"CFBundleVersion" ])
);
if (loadedKexts[@(USERCLIENT_ID)] && loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"]) {
if (loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"]) {
return loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"];
}

View File

@@ -26,6 +26,8 @@
// Globals used by the santad watchdog thread
uint64_t watchdogCPUEvents = 0;
uint64_t watchdogRAMEvents = 0;
double watchdogCPUPeak = 0;
double watchdogRAMPeak = 0;
@interface SNTDaemonControlController ()
@property dispatch_source_t syncTimer;
@@ -94,12 +96,14 @@ uint64_t watchdogRAMEvents = 0;
reply([rdb binaryRuleCount], [rdb certificateRuleCount]);
}
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply {
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate
reply:(void (^)(BOOL success))reply {
[self databaseRuleAddRules:@[ rule ] cleanSlate:cleanSlate reply:reply];
}
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply {
[[SNTDatabaseController ruleTable] addRules:rules cleanSlate:cleanSlate];
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate
reply:(void (^)(BOOL success))reply {
BOOL success = [[SNTDatabaseController ruleTable] addRules:rules cleanSlate:cleanSlate];
// If any rules were added that were not whitelist, flush cache.
NSPredicate *p = [NSPredicate predicateWithFormat:@"SELF.state != %d", RULESTATE_WHITELIST];
@@ -108,7 +112,7 @@ uint64_t watchdogRAMEvents = 0;
[self.driverManager flushCache];
}
reply();
reply(success);
}
- (void)databaseEventCount:(void (^)(int64_t count))reply {
@@ -170,12 +174,8 @@ uint64_t watchdogRAMEvents = 0;
reply();
}
- (void)watchdogCPUEvents:(void (^)(uint64_t))reply {
reply(watchdogCPUEvents);
}
- (void)watchdogRAMEvents:(void (^)(uint64_t))reply {
reply(watchdogRAMEvents);
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply {
reply(watchdogCPUEvents, watchdogRAMEvents, watchdogCPUPeak, watchdogRAMPeak);
}
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
// This is imported in the header rather than implementation to saves
// This is imported in the header rather than implementation to save
// classes that use this one from also having to import FMDB stuff.
#import <FMDB/FMDB.h>

View File

@@ -14,6 +14,7 @@
#import "SNTKernelCommon.h"
@class SNTCachedDecision;
///

View File

@@ -14,11 +14,11 @@
#import "SNTEventLog.h"
#include <sys/stat.h>
#include <libproc.h>
#include <sys/sysctl.h>
#import "SNTCachedDecision.h"
#import "SNTCertificate.h"
#import "MOLCertificate.h"
#import "SNTCommonEnums.h"
#import "SNTFileInfo.h"
#import "SNTKernelCommon.h"
@@ -69,11 +69,8 @@
}
case ACTION_NOTIFY_WRITE: {
action = @"WRITE";
struct stat filestat;
stat(message.path, &filestat);
if (filestat.st_size < 1024 * 1024) {
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:path];
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:path];
if (fileInfo.fileSize < 1024 * 1024) {
sha256 = fileInfo.SHA256;
} else {
sha256 = @"(too large)";
@@ -87,8 +84,13 @@
if (newpath) {
outStr = [outStr stringByAppendingFormat:@"|newpath=%@", [self sanitizeString:newpath]];
}
outStr = [outStr stringByAppendingFormat:@"|pid=%d|ppid=%d|uid=%d|gid=%d",
message.pid, message.ppid, message.uid, message.gid];
char ppath[PATH_MAX];
if (proc_pidpath(message.pid, ppath, PATH_MAX) < 1) {
strncpy(ppath, "(null)", 6);
}
outStr =
[outStr stringByAppendingFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|gid=%d",
message.pid, message.ppid, message.pname, ppath, message.uid, message.gid];
if (sha256) {
outStr = [outStr stringByAppendingFormat:@"|sha256=%@", sha256];
}

View File

@@ -14,7 +14,7 @@
#import "SNTEventTable.h"
#import "SNTCertificate.h"
#import "MOLCertificate.h"
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
@@ -43,7 +43,12 @@
!event.occurrenceDate ||
!event.decision) return NO;
NSData *eventData = [NSKeyedArchiver archivedDataWithRootObject:event];
NSData *eventData;
@try {
eventData = [NSKeyedArchiver archivedDataWithRootObject:event];
} @catch (NSException *exception) {
return NO;
}
__block BOOL success = NO;
[self inTransaction:^(FMDatabase *db, BOOL *rollback) {
@@ -73,6 +78,9 @@
if ([rs next]) {
storedEvent = [self eventFromResultSet:rs];
if (!storedEvent) {
[db executeUpdate:@"DELETE FROM events WHERE idx=?", [rs objectForColumnName:@"idx"]];
}
}
[rs close];
@@ -92,8 +100,7 @@
if (obj) {
[pendingEvents addObject:obj];
} else {
NSNumber *idx = [rs objectForColumnName:@"idx"];
[db executeUpdate:@"DELETE FROM events WHERE idx=?", idx];
[db executeUpdate:@"DELETE FROM events WHERE idx=?", [rs objectForColumnName:@"idx"]];
}
}
@@ -107,8 +114,12 @@
NSData *eventData = [rs dataForColumn:@"eventdata"];
if (!eventData) return nil;
SNTStoredEvent *event = [NSKeyedUnarchiver unarchiveObjectWithData:eventData];
event.idx = @([rs intForColumn:@"idx"]);
SNTStoredEvent *event;
@try {
event = [NSKeyedUnarchiver unarchiveObjectWithData:eventData];
event.idx = @([rs intForColumn:@"idx"]);
} @catch (NSException *exception) {}
return event;
}

View File

@@ -15,7 +15,7 @@
#include "SNTCommonEnums.h"
#include "SNTKernelCommon.h"
@class SNTCodesignChecker;
@class MOLCodesignChecker;
@class SNTDriverManager;
@class SNTEventLog;
@class SNTEventTable;

View File

@@ -21,8 +21,8 @@
#include "SNTLogging.h"
#import "SNTCachedDecision.h"
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import "SNTCommonEnums.h"
#import "SNTConfigurator.h"
#import "SNTDriverManager.h"
@@ -56,7 +56,7 @@
// Workaround for xpcproxy/libsecurity bug on Yosemite
// This establishes the XPC connection between libsecurity and syspolicyd.
// Not doing this causes a deadlock as establishing this link goes through xpcproxy.
(void)[[SNTCodesignChecker alloc] initWithSelf];
(void)[[MOLCodesignChecker alloc] initWithSelf];
}
return self;
}
@@ -123,7 +123,7 @@
}
// Get codesigning info about the file.
SNTCodesignChecker *csInfo = [[SNTCodesignChecker alloc] initWithBinaryPath:binInfo.path];
MOLCodesignChecker *csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path];
// Actually make the decision.
SNTCachedDecision *cd = [[SNTCachedDecision alloc] init];
@@ -137,10 +137,6 @@
santa_action_t action = [self actionForEventState:cd.decision];
if (action == ACTION_RESPOND_CHECKBW_ALLOW) [self.eventLog saveDecisionDetails:cd];
// Get name of parent process. Do this before responding to be sure parent doesn't go away.
char pname[PROC_PIDPATHINFO_MAXSIZE];
proc_name(message.ppid, pname, PROC_PIDPATHINFO_MAXSIZE);
// Send the decision to the kernel.
[self.driverManager postToKernelAction:action forVnodeID:cd.vnodeId];
@@ -158,7 +154,7 @@
se.signingChain = csInfo.certificates;
se.pid = @(message.pid);
se.ppid = @(message.ppid);
se.parentName = @(pname);
se.parentName = @(message.pname);
se.fileBundleID = [binInfo bundleIdentifier];
se.fileBundleName = [binInfo bundleName];
@@ -182,6 +178,11 @@
se.currentSessions = currentSessions;
se.loggedInUsers = loggedInUsers;
se.quarantineDataURL = binInfo.quarantineDataURL;
se.quarantineRefererURL = binInfo.quarantineRefererURL;
se.quarantineTimestamp = binInfo.quarantineTimestamp;
se.quarantineAgentBundleID = binInfo.quarantineAgentBundleID;
[self.eventTable addStoredEvent:se];
// If binary was blocked, do the needful
@@ -232,7 +233,9 @@
return @"Blacklist Regex";
}
if (fi.isMissingPageZero) return @"Missing __PAGEZERO";
if ([[SNTConfigurator configurator] enablePageZeroProtection] && fi.isMissingPageZero) {
return @"Missing __PAGEZERO";
}
return nil;
}

View File

@@ -14,15 +14,25 @@
#import "SNTRuleTable.h"
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import "SNTConfigurator.h"
#import "SNTLogging.h"
#import "SNTRule.h"
@interface SNTRuleTable ()
@property NSString *santadCertSHA;
@property NSString *launchdCertSHA;
@end
@implementation SNTRuleTable
- (uint32_t)initializeDatabase:(FMDatabase *)db fromVersion:(uint32_t)version {
// Save hashes of the signing certs for launchd and santad
self.santadCertSHA = [[[[MOLCodesignChecker alloc] initWithSelf] leafCertificate] SHA256];
self.launchdCertSHA = [[[[MOLCodesignChecker alloc] initWithPID:1] leafCertificate] SHA256];
uint32_t newVersion = 0;
if (version < 1) {
@@ -41,12 +51,10 @@
// Insert the codesigning certs for the running santad and launchd into the initial database.
// This helps prevent accidentally denying critical system components while the database
// is empty. This 'initial database' will then be cleared on the first successful sync.
NSString *santadSHA = [[[[SNTCodesignChecker alloc] initWithSelf] leafCertificate] SHA256];
NSString *launchdSHA = [[[[SNTCodesignChecker alloc] initWithPID:1] leafCertificate] SHA256];
[db executeUpdate:@"INSERT INTO rules (shasum, state, type) VALUES (?, ?, ?)",
santadSHA, @(RULESTATE_WHITELIST), @(RULETYPE_CERT)];
self.santadCertSHA, @(RULESTATE_WHITELIST), @(RULETYPE_CERT)];
[db executeUpdate:@"INSERT INTO rules (shasum, state, type) VALUES (?, ?, ?)",
launchdSHA, @(RULESTATE_WHITELIST), @(RULETYPE_CERT)];
self.launchdCertSHA, @(RULESTATE_WHITELIST), @(RULETYPE_CERT)];
newVersion = 1;
@@ -124,14 +132,28 @@
#pragma mark Adding
- (BOOL)addRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate {
__block BOOL failed = NO;
if (!rules || rules.count < 1) {
LOGE(@"Received request to add rules with nil/empty array.");
return NO;
}
__block BOOL failed = NO;
[self inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Protect rules for santad/launchd certificates.
NSPredicate *p = [NSPredicate predicateWithFormat:
@"(SELF.shasum = %@ OR SELF.shasum = %@) AND SELF.type = %d",
self.santadCertSHA, self.launchdCertSHA, RULETYPE_CERT];
NSArray *requiredHashes = [rules filteredArrayUsingPredicate:p];
p = [NSPredicate predicateWithFormat:@"SELF.state == %d", RULESTATE_WHITELIST];
NSArray *requiredHashesWhitelist = [requiredHashes filteredArrayUsingPredicate:p];
if ((cleanSlate && requiredHashesWhitelist.count != 2) ||
(requiredHashes.count != requiredHashesWhitelist.count)) {
LOGE(@"Received request to remove whitelist for launchd/santad ceritifcates.");
*rollback = failed = YES;
return;
}
if (cleanSlate) {
[db executeUpdate:@"DELETE FROM rules"];
}

View File

@@ -21,10 +21,12 @@
extern uint64_t watchdogCPUEvents;
extern uint64_t watchdogRAMEvents;
extern double watchdogCPUPeak;
extern double watchdogRAMPeak;
/// Converts a timeval struct to double, converting the microseconds value to seconds.
static inline double timeval_to_double(struct timeval tv) {
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
static inline double timeval_to_double(time_value_t tv) {
return (double)tv.seconds + (double)tv.microseconds / 1000000.0;
}
/// The watchdog thread function, used to monitor santad CPU/RAM usage and print a warning
@@ -45,36 +47,39 @@ void *watchdogThreadFunction(__unused void *idata) {
double prevTotalTime = 0.0;
double prevRamUseMB = 0.0;
struct rusage usage;
struct mach_task_basic_info taskInfo;
mach_msg_type_number_t taskInfoCount = MACH_TASK_BASIC_INFO_COUNT;
while(true) {
@autoreleasepool {
sleep(timeInterval);
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
(task_info_t)&taskInfo, &taskInfoCount) == KERN_SUCCESS) {
// CPU
double totalTime = (timeval_to_double(taskInfo.user_time) +
timeval_to_double(taskInfo.system_time));
double percentage = (((totalTime - prevTotalTime) / (double)timeInterval) * 100.0);
prevTotalTime = totalTime;
// CPU
getrusage(RUSAGE_SELF, &usage);
double totalTime = timeval_to_double(usage.ru_utime) + timeval_to_double(usage.ru_stime);
double percentage = (((totalTime - prevTotalTime) / (double)timeInterval) * 100.0);
prevTotalTime = totalTime;
if (percentage > cpuWarnThreshold) {
LOGW(@"Watchdog: potentially high CPU use, ~%.2f%% over last %d seconds.",
percentage, timeInterval);
watchdogCPUEvents++;
}
if (percentage > cpuWarnThreshold) {
LOGW(@"Watchdog: potentially high CPU use, ~%.2f%% over last %d seconds.",
percentage, timeInterval);
watchdogCPUEvents++;
}
if (percentage > watchdogCPUPeak) watchdogCPUPeak = percentage;
// RAM
if (KERN_SUCCESS == task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
(task_info_t)&taskInfo, &taskInfoCount)) {
double ramUseMB = (double) taskInfo.resident_size / 1024 / 1024;
// RAM
double ramUseMB = (double)taskInfo.resident_size / 1024 / 1024;
if (ramUseMB > memWarnThreshold && ramUseMB > prevRamUseMB) {
LOGW(@"Watchdog: potentially high RAM use, RSS is %.2fMB.", ramUseMB);
watchdogRAMEvents++;
}
prevRamUseMB = ramUseMB;
if (ramUseMB > watchdogRAMPeak) watchdogRAMPeak = ramUseMB;
}
sleep(timeInterval);
}
}
return NULL;

View File

@@ -1,243 +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 <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "SNTCertificate.h"
@interface SNTCertificate (Testing)
- (NSString *)x509ValueForLabel:(NSString *)desiredLabel fromDictionary:(NSDictionary *)dict;
- (NSDate *)dateForX509Key:(NSString *)key;
@end
@interface SNTCertificateTest : XCTestCase
@property NSString *testDataPEM1;
@property NSString *testDataPEM2;
@property NSData *testDataDER1;
@property NSData *testDataDER2;
@property NSString *testDataPrivateKey;
@end
@implementation SNTCertificateTest
- (void)setUp {
[super setUp];
NSString *file = [[NSBundle bundleForClass:[self class]] pathForResource:@"GIAG2" ofType:@"pem"];
self.testDataPEM1 = [NSString stringWithContentsOfFile:file
encoding:NSUTF8StringEncoding
error:nil];
file = [[NSBundle bundleForClass:[self class]] pathForResource:@"apple" ofType:@"pem"];
self.testDataPEM2 = [NSString stringWithContentsOfFile:file
encoding:NSUTF8StringEncoding
error:nil];
file = [[NSBundle bundleForClass:[self class]] pathForResource:@"GIAG2" ofType:@"crt"];
self.testDataDER1 = [NSData dataWithContentsOfFile:file];
file = [[NSBundle bundleForClass:[self class]] pathForResource:@"tubitak" ofType:@"crt"];
self.testDataDER2 = [NSData dataWithContentsOfFile:file];
self.testDataPrivateKey = @"-----BEGIN RSA PRIVATE KEY-----"
@"MIICXQIBAAKBgQDk2F9JsQQjKSveMwazXzFLbiiOD0RkDiRX1LTmQtVdi514F6l/"
@"RwohMrwxQpsoKwyzEngX58+PrGZ0XZrcVcHn666521IxswHZPaacBlWZ7k9XkB2Y"
@"m8mxULMBG9iIv/k5tRJN3MuJdtbQc8qLBsyFFsytL8hSRvBQNyP7N/OqnQIDAQAB"
@"AoGATpLUNNMonoH2Y/aVKGVY4ZNTLWOkkc4hQF7yNdVguRvE14UYV3Em0zs+TpOV"
@"/na5h4qh3WNkaupAy1eQYnK3fqmGLZw5e8cBCgUkIi8P//zMrKlgJKwfzQHSdJSP"
@"pkCvj2kliFwNzbA026jcwGEYV+uRCNazO5ldtOcP5EDb+qkCQQD/Ihc2mjtf7oq1"
@"VZSzo0xch3NtzTZMyFCRWqMpXHQO1fZTAe96EbI85zsTRmOVuqKnGxBvvtHJr2QY"
@"UoZ72+f7AkEA5Z9qte46t1F1ME3ZzWd6Ob1obCmuAa75eTPAgQKc+1bSVeFMGLTz"
@"n2M9wZ+mIpWvJp8QRdmOi0zpEArHqa68RwJBAO1YoY/CW4obOB8JxpR3TgqmV9PG"
@"HMXBdHJEh5Vq1O0YT1dZbZd57v6JfoOn7+zS+43Jt7i9JB0kdVHLNCD1qxECQQC3"
@"wXGGEhVO6pMbitGHvQ1k85yDIn+rvTjLs4yUMWErCfnc3CUniHeFz8d2EarD9oFq"
@"KNS+8TFPbMb+HYJW2gy1AkAHGBUKmZNPGiKJEUjc5jN1uN+B9OMLDX+3rMUO9Q2x"
@"jsn0m7Mobx+pPqbIAvsklMtA4Qdrt5a9pnwEgTWoJPYA"
@"-----END RSA PRIVATE KEY-----";
}
- (void)tearDown {
[super tearDown];
}
- (void)testInitWithDER {
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataDER:self.testDataDER1];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName, @"Google Internet Authority G2");
XCTAssertEqualObjects(sut.orgUnit, nil);
XCTAssertEqualObjects(sut.orgName, @"Google Inc");
XCTAssertEqualObjects(sut.countryName, @"US");
XCTAssertEqualObjects(sut.issuerCommonName, @"GeoTrust Global CA");
XCTAssertEqualObjects(sut.issuerOrgName, @"GeoTrust Inc.");
XCTAssertEqualObjects(sut.issuerOrgUnit, nil);
XCTAssertEqualObjects(sut.issuerCountryName, @"US");
XCTAssertEqualObjects(sut.SHA1, @"d83c1a7f4d0446bb2081b81a1670f8183451ca24");
XCTAssertEqualObjects(sut.SHA256,
@"a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d");
XCTAssertEqualObjects(sut.validFrom, [NSDate dateWithString:@"2013-04-05 15:15:55 +0000"]);
XCTAssertEqualObjects(sut.validUntil, [NSDate dateWithString:@"2015-04-04 15:15:55 +0000"]);
sut = [[SNTCertificate alloc] initWithCertificateDataDER:self.testDataDER2];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName,
@"TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3");
XCTAssertEqualObjects(sut.orgUnit,
@"Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE");
XCTAssertEqualObjects(sut.orgName,
@"Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK");
XCTAssertEqualObjects(sut.countryName, @"TR");
}
- (void)testInitWithValidPEM {
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName, @"Google Internet Authority G2");
XCTAssertEqualObjects(sut.orgUnit, nil);
XCTAssertEqualObjects(sut.orgName, @"Google Inc");
XCTAssertEqualObjects(sut.issuerCommonName, @"GeoTrust Global CA");
XCTAssertEqualObjects(sut.SHA1, @"d83c1a7f4d0446bb2081b81a1670f8183451ca24");
XCTAssertEqualObjects(sut.SHA256,
@"a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d");
XCTAssertEqualObjects(sut.validFrom, [NSDate dateWithString:@"2013-04-05 15:15:55 +0000"]);
XCTAssertEqualObjects(sut.validUntil, [NSDate dateWithString:@"2015-04-04 15:15:55 +0000"]);
XCTAssertTrue(sut.isCA);
XCTAssertEqualObjects(sut.serialNumber, @"146025");
sut = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM2];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName, @"www.apple.com");
XCTAssertEqualObjects(sut.orgUnit, @"ISG for Akamai");
XCTAssertEqualObjects(sut.orgName, @"Apple Inc.");
XCTAssertEqualObjects(sut.issuerCommonName, @"VeriSign Class 3 Extended Validation SSL SGC CA");
XCTAssertEqualObjects(sut.issuerOrgName, @"VeriSign, Inc.");
XCTAssertEqualObjects(sut.issuerOrgUnit, @"VeriSign Trust Network");
XCTAssertEqualObjects(sut.SHA1, @"96df534f6f4306ca474d9078fc346b20f856f0d4");
XCTAssertEqualObjects(sut.SHA256,
@"129d39ff4384197dc2bcbe1a83a69b3405b7df33254b1b1ee29a23847a23555a");
XCTAssertEqualObjects(sut.validFrom, [NSDate dateWithString:@"2013-11-14 00:00:00 +0000"]);
XCTAssertEqualObjects(sut.validUntil, [NSDate dateWithString:@"2015-11-14 23:59:59 +0000"]);
XCTAssertFalse(sut.isCA);
XCTAssertEqualObjects(sut.serialNumber, @"5E FA 67 0E 99 E4 AB 88 E0 F2 0B 33 86 7B 78 4D");
}
- (void)testInitWithValidPEMAfterKey {
NSString *pemWithKey = [self.testDataPrivateKey stringByAppendingString:self.testDataPEM1];
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:pemWithKey];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName, @"Google Internet Authority G2");
}
- (void)testInitWithEmptyPEM {
NSString *badPEM = @"-----BEGIN CERTIFICATE----------END CERTIFICATE-----";
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:badPEM];
XCTAssertNil(sut);
}
- (void)testInitWithTruncatedPEM {
NSString *badPEM = @"-----BEGIN CERTIFICATE-----"
@"MIICXQIBAAKBgQDk2F9JsQQjKSveMwazXzFLbiiOD0RkDiRX1LTmQtVdi514F6l/";
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:badPEM];
XCTAssertNil(sut);
}
- (void)testInitWithInvalidPEM {
NSString *badPEM = @"This is not a valid PEM";
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:badPEM];
XCTAssertNil(sut);
badPEM = @"-----BEGIN CERTIFICATE-----Hello Thar-----END CERTIFICATE-----";
sut = [[SNTCertificate alloc] initWithCertificateDataPEM:badPEM];
XCTAssertNil(sut);
}
- (void)testInitWithMultipleCertsInPEM {
NSString *multiPEM = [self.testDataPEM1 stringByAppendingString:self.testDataPEM2];
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:multiPEM];
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.commonName, @"Google Internet Authority G2");
}
- (void)testArrayOfCerts {
NSString *multiPEM = [self.testDataPEM1 stringByAppendingString:self.testDataPEM2];
NSArray *certs = [SNTCertificate certificatesFromPEM:multiPEM];
XCTAssertNotNil(certs);
XCTAssertEqual(certs.count, 2);
XCTAssertEqualObjects([certs[0] commonName], @"Google Internet Authority G2");
XCTAssertEqualObjects([certs[1] commonName], @"www.apple.com");
}
- (void)testPlainInit {
XCTAssertThrows([[SNTCertificate alloc] init]);
}
- (void)testEquals {
SNTCertificate *sut1 = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
SNTCertificate *sut2 = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
XCTAssertEqualObjects(sut1, sut2);
}
- (void)testDescription {
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
XCTAssertEqualObjects([sut description], @"/O=Google Inc/OU=(null)/CN=Google Internet Authority G2");
}
- (void)testSecureCoding {
XCTAssertTrue([SNTCertificate supportsSecureCoding]);
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
NSMutableData *encodedObject = [[NSMutableData alloc] init];
NSKeyedArchiver *archive = [[NSKeyedArchiver alloc] initForWritingWithMutableData:encodedObject];
[archive encodeObject:sut forKey:@"exampleCert"];
[archive finishEncoding];
NSKeyedUnarchiver *unarchive = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedObject];
SNTCertificate *newCert = [unarchive decodeObjectForKey:@"exampleCert"];
XCTAssertNotNil(newCert);
XCTAssertEqualObjects(newCert, sut);
XCTAssertEqualObjects(newCert.SHA1, sut.SHA1);
}
- (void)testCachingAccessors {
SNTCertificate *sut = [[SNTCertificate alloc] initWithCertificateDataPEM:self.testDataPEM1];
id sutMock = OCMPartialMock(sut);
// Access each of the properties to get them cached
(void)sut.orgName;
(void)sut.issuerCommonName;
(void)sut.validFrom;
(void)sut.countryName;
(void)sut.issuerCountryName;
// Now break some of the properties
OCMExpect([sutMock x509ValueForLabel:OCMOCK_ANY fromDictionary:OCMOCK_ANY]);
OCMExpect([sutMock dateForX509Key:OCMOCK_ANY]);
XCTAssertEqualObjects(sut.orgName, @"Google Inc");
XCTAssertEqualObjects(sut.issuerCommonName, @"GeoTrust Global CA");
XCTAssertEqualObjects(sut.validFrom, [NSDate dateWithString:@"2013-04-05 15:15:55 +0000"]);
XCTAssertEqualObjects(sut.countryName, @"US");
XCTAssertEqualObjects(sut.issuerCountryName, @"US");
}
@end

View File

@@ -1,103 +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/XCTest.h>
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
/**
Tests for @c SNTCodesignChecker
Most of these tests rely on some facts about @c launchd:
* launchd is in /sbin
* launchd is PID 1
* launchd is signed
* launchd's leaf cert has a CN of "Software Signing"
* launchd's leaf cert has an OU of "Apple Software"
* launchd's leaf cert has an ON of "Apple Inc."
These facts are pretty stable, so shouldn't be a problem.
**/
@interface SNTCodesignCheckerTest : XCTestCase
@end
@implementation SNTCodesignCheckerTest
- (void)testInitWithBinaryPath {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithBinaryPath:@"/sbin/launchd"];
XCTAssertNotNil(sut);
}
- (void)testInitWithInvalidBinaryPath {
SNTCodesignChecker *sut =
[[SNTCodesignChecker alloc] initWithBinaryPath:@"/tmp/this/file/doesnt/exist"];
XCTAssertNil(sut);
}
- (void)testInitWithPID {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertNotNil(sut);
}
- (void)testInitWithInvalidPID {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:999999999];
XCTAssertNil(sut);
}
- (void)testInitWithSelf {
// n.b: 'self' in this case is xctest, which should always be signed.
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithSelf];
XCTAssertNotNil(sut);
}
- (void)testPlainInit {
XCTAssertThrows([[SNTCodesignChecker alloc] init]);
}
- (void)testDescription {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertEqualObjects([sut description],
@"In-memory binary, signed by Apple Inc., located at: /sbin/launchd");
}
- (void)testLeafCertificate {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertNotNil(sut.leafCertificate);
}
- (void)testBinaryPath {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertEqualObjects(sut.binaryPath, @"/sbin/launchd");
}
- (void)testSigningInformationMatches {
SNTCodesignChecker *sut1 = [[SNTCodesignChecker alloc] initWithBinaryPath:@"/sbin/launchd"];
SNTCodesignChecker *sut2 = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertTrue([sut1 signingInformationMatches:sut2]);
}
- (void)testCodeRef {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithSelf];
XCTAssertNotNil((id)sut.codeRef);
}
- (void)testSigningInformation {
SNTCodesignChecker *sut = [[SNTCodesignChecker alloc] initWithPID:1];
XCTAssertNotNil(sut.signingInformation);
XCTAssertEqualObjects(sut.signingInformation[@"source"], @"embedded");
}
@end

View File

@@ -14,7 +14,7 @@
#import <XCTest/XCTest.h>
#import "SNTCodesignChecker.h"
#import "MOLCodesignChecker.h"
#import "SNTEventTable.h"
#import "SNTFileInfo.h"
#import "SNTStoredEvent.h"
@@ -24,8 +24,8 @@
/// Adding/Retrieving events relies on SNTStoredEvent coding to work correctly
/// so if that is broken, these tests will fail.
///
/// Depends on on SNTFileInfo and SNTCodesignChecker (and by extension
/// SNTCertificate) to avoid duplicating code into these tests.
/// Depends on on SNTFileInfo and MOLCodesignChecker (and by extension
/// MOLCertificate) to avoid duplicating code into these tests.
///
@interface SNTEventTableTest : XCTestCase
@property SNTEventTable *sut;
@@ -43,7 +43,7 @@
- (SNTStoredEvent *)createTestEvent {
SNTFileInfo *binInfo = [[SNTFileInfo alloc] initWithPath:@"/usr/bin/false"];
SNTCodesignChecker *csInfo = [[SNTCodesignChecker alloc] initWithBinaryPath:@"/usr/bin/false"];
MOLCodesignChecker *csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:@"/usr/bin/false"];
SNTStoredEvent *event;
event = [[SNTStoredEvent alloc] init];
event.filePath = @"/usr/bin/false";

View File

@@ -17,8 +17,8 @@
#import "SNTExecutionController.h"
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import "SNTConfigurator.h"
#import "SNTDriverManager.h"
#import "SNTEventTable.h"
@@ -44,7 +44,7 @@
fclose(stdout);
self.mockCodesignChecker = OCMClassMock([SNTCodesignChecker class]);
self.mockCodesignChecker = OCMClassMock([MOLCodesignChecker class]);
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY])
.andReturn(self.mockCodesignChecker);
@@ -121,7 +121,7 @@
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
id cert = OCMClassMock([SNTCertificate class]);
id cert = OCMClassMock([MOLCertificate class]);
OCMStub([self.mockCodesignChecker leafCertificate]).andReturn(cert);
OCMStub([cert SHA256]).andReturn(@"a");
@@ -139,7 +139,7 @@
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
id cert = OCMClassMock([SNTCertificate class]);
id cert = OCMClassMock([MOLCertificate class]);
OCMStub([self.mockCodesignChecker leafCertificate]).andReturn(cert);
OCMStub([cert SHA256]).andReturn(@"a");

View File

@@ -17,6 +17,11 @@
#import "SNTRule.h"
#import "SNTRuleTable.h"
@interface SNTRuleTable (Testing)
@property NSString *santadCertSHA;
@property NSString *launchdCertSHA;
@end
/// This test case actually tests SNTRuleTable and SNTRule
@interface SNTRuleTableTest : XCTestCase
@property SNTRuleTable *sut;
@@ -60,22 +65,36 @@
}
- (void)testAddRulesClean {
// If SNTRuleTable doesn't start with some rules, this test doesn't work properly.
XCTAssert(self.sut.ruleCount);
// Assert that insert without 'self' and launchd cert hashes fails
XCTAssertFalse([self.sut addRules:@[ [self _exampleBinaryRule] ] cleanSlate:YES]);
[self.sut addRules:@[ [self _exampleBinaryRule] ] cleanSlate:YES];
// Now add a binary rule without clean slate
XCTAssertTrue([self.sut addRules:@[ [self _exampleBinaryRule] ] cleanSlate:NO]);
XCTAssertEqual(self.sut.ruleCount, 1);
XCTAssertEqual(self.sut.binaryRuleCount, 1);
// Now add a cert rule + the required rules as a clean slate,
// assert that the binary rule was removed
SNTRule *r1 = [[SNTRule alloc] init];
r1.shasum = self.sut.launchdCertSHA;
r1.state = RULESTATE_WHITELIST;
r1.type = RULETYPE_CERT;
SNTRule *r2 = [[SNTRule alloc] init];
r2.shasum = self.sut.santadCertSHA;
r2.state = RULESTATE_WHITELIST;
r2.type = RULETYPE_CERT;
XCTAssertTrue(([self.sut addRules:@[ [self _exampleCertRule], r1, r2 ] cleanSlate:YES]));
XCTAssertEqual([self.sut binaryRuleCount], 0);
}
- (void)testAddMultipleRules {
NSUInteger ruleCount = self.sut.ruleCount;
[self.sut addRules:@[ [self _exampleBinaryRule],
[self _exampleCertRule],
[self _exampleBinaryRule] ]
cleanSlate:YES];
cleanSlate:NO];
XCTAssertEqual(self.sut.ruleCount, 2);
XCTAssertEqual(self.sut.ruleCount, ruleCount + 2);
}
- (void)testAddRulesEmptyArray {
@@ -87,7 +106,7 @@
}
- (void)testFetchBinaryRule {
[self.sut addRules:@[ [self _exampleBinaryRule], [self _exampleCertRule] ] cleanSlate:YES];
[self.sut addRules:@[ [self _exampleBinaryRule], [self _exampleCertRule] ] cleanSlate:NO];
SNTRule *r = [self.sut binaryRuleForSHA256:@"a"];
XCTAssertNotNil(r);
@@ -99,7 +118,7 @@
}
- (void)testFetchCertificateRule {
[self.sut addRules:@[ [self _exampleBinaryRule], [self _exampleCertRule] ] cleanSlate:YES];
[self.sut addRules:@[ [self _exampleBinaryRule], [self _exampleCertRule] ] cleanSlate:NO];
SNTRule *r = [self.sut certificateRuleForSHA256:@"b"];
XCTAssertNotNil(r);

View File

@@ -15,7 +15,7 @@
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "SNTCodesignChecker.h"
#import "MOLCodesignChecker.h"
#import "SNTXPCConnection.h"
@interface SNTXPCConnection (Testing)
@@ -100,7 +100,7 @@
OCMExpect([self.mockConnection processIdentifier]).andReturn(1);
id mockCodesignChecker = OCMClassMock([SNTCodesignChecker class]);
id mockCodesignChecker = OCMClassMock([MOLCodesignChecker class]);
OCMExpect([mockCodesignChecker alloc]).andReturn(mockCodesignChecker);
OCMExpect([mockCodesignChecker signingInformationMatches:OCMOCK_ANY]).andReturn(NO);