mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
437764e6fc | ||
|
|
460dd6aa8b | ||
|
|
0a511468e3 | ||
|
|
96517573e7 | ||
|
|
c996921c22 | ||
|
|
8365e00a50 | ||
|
|
a629e6cff1 | ||
|
|
cbb786c6d1 | ||
|
|
49b169ec36 | ||
|
|
41d1d7e3de | ||
|
|
323a38dc21 | ||
|
|
c37f1eb006 | ||
|
|
b7b2b5b630 | ||
|
|
2486cfdcff | ||
|
|
4231781178 | ||
|
|
7ba886ed18 | ||
|
|
8096701fbd | ||
|
|
16531d18c8 | ||
|
|
ef0cc2fffd | ||
|
|
f2dc7fb4b0 | ||
|
|
707e9a11d4 | ||
|
|
aef3d57dcf | ||
|
|
cfb38068f8 | ||
|
|
ca19d9fde7 | ||
|
|
e19aab36bd | ||
|
|
111540f0a8 | ||
|
|
88897477b6 | ||
|
|
a9d6e42d5a | ||
|
|
8b5720b291 | ||
|
|
2d9f392efc | ||
|
|
76844eb77d | ||
|
|
2db996f8e0 | ||
|
|
6c27ac60a1 | ||
|
|
d4c4b26c3b | ||
|
|
50614f589c | ||
|
|
0292d4e956 | ||
|
|
4e1e4cde3b | ||
|
|
c86f0e7c80 | ||
|
|
77b8edda79 | ||
|
|
f3d098c521 | ||
|
|
0afe465ac5 | ||
|
|
472558a03c | ||
|
|
dfef7d8567 | ||
|
|
925903e07d | ||
|
|
a43c0ee295 | ||
|
|
1e82b5abc6 | ||
|
|
7502dbdec6 | ||
|
|
217ad25531 | ||
|
|
7c3b533679 | ||
|
|
2c4ba45988 | ||
|
|
26ee0a68d1 | ||
|
|
27eb2e9cff | ||
|
|
9431d954b5 | ||
|
|
1a2d8b55f8 | ||
|
|
d27a26ca50 | ||
|
|
56d4a6b9fb | ||
|
|
28a94cd56a | ||
|
|
4344fc3d7d | ||
|
|
40431d835e | ||
|
|
942804c478 | ||
|
|
d109aae6ef | ||
|
|
b89040c37a | ||
|
|
63aefb4654 | ||
|
|
1c92e968e3 | ||
|
|
c1b7f9ae63 | ||
|
|
0507bc83d2 | ||
|
|
7028c24425 | ||
|
|
6ede057521 | ||
|
|
6f2ccca60a |
@@ -2,9 +2,7 @@
|
||||
language: objective-c
|
||||
|
||||
before_install:
|
||||
- gem install cocoapods
|
||||
- brew update
|
||||
- brew upgrade xctool
|
||||
- gem install cocoapods xcpretty
|
||||
|
||||
script:
|
||||
- xctool -workspace Santa.xcworkspace -scheme All build test CODE_SIGN_IDENTITY=''
|
||||
- xcodebuild -workspace Santa.xcworkspace -scheme All build test CODE_SIGN_IDENTITY='' | xcpretty -sc && exit ${PIPESTATUS[0]}
|
||||
|
||||
12
Podfile
12
Podfile
@@ -4,6 +4,18 @@ inhibit_all_warnings!
|
||||
|
||||
target :santad do
|
||||
pod 'FMDB'
|
||||
|
||||
post_install do |rep|
|
||||
rep.project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
if config.name != 'Release' then
|
||||
break
|
||||
end
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ''
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] <<= "NDEBUG=1"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
target :LogicTests do
|
||||
|
||||
@@ -11,7 +11,7 @@ DEPENDENCIES:
|
||||
- OCMock
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FMDB: 0efa188cf0dd1ce82c27a478cd5f5fa245308677
|
||||
OCMock: ecdd510b73ef397f2f97274785c1e87fd147c49f
|
||||
FMDB: 96e8f1bcc1329e269330f99770ad4285d9003e52
|
||||
OCMock: a10ea9f0a6e921651f96f78b6faee95ebc813b92
|
||||
|
||||
COCOAPODS: 0.35.0
|
||||
COCOAPODS: 0.36.1
|
||||
|
||||
@@ -51,16 +51,9 @@ Known Issues
|
||||
|
||||
Santa is not yet a 1.0 and we have some known issues to be aware of:
|
||||
|
||||
* Potential race-condition: we currently have a single TODO in the kext code to
|
||||
investigate a potential race condition where a binary is executed and then very
|
||||
quickly modified between the kext getting the SHA-1 and the decision being made.
|
||||
|
||||
* Kext communication security: the kext will only accept a connection from a
|
||||
single client at a time and said client must be running as root. We haven't yet
|
||||
found a good way to ensure the kext only accepts connections from a valid client,
|
||||
short of hardcoding the SHA-1 in the kext. This shouldn't present a huge problem
|
||||
as the daemon is loaded on boot-up by launchd, so any later attempts to connect
|
||||
will be blocked.
|
||||
found a good way to ensure the kext only accepts connections from a valid client.
|
||||
|
||||
* Database protection: the SQLite database is installed with permissions so that
|
||||
only the root user can read/write it. We're considering approaches to secure
|
||||
|
||||
69
Rakefile
69
Rakefile
@@ -1,46 +1,24 @@
|
||||
require 'timeout'
|
||||
|
||||
WORKSPACE = 'Santa.xcworkspace'
|
||||
DEFAULT_SCHEME = 'All'
|
||||
OUTPUT_PATH = 'Build'
|
||||
DIST_PATH = 'Dist'
|
||||
BINARIES = ['Santa.app', 'santa-driver.kext', 'santad', 'santactl']
|
||||
XCTOOL_DEFAULTS = "-workspace #{WORKSPACE} -scheme #{DEFAULT_SCHEME}"
|
||||
XCODE_DEFAULTS = "-workspace #{WORKSPACE} -scheme #{DEFAULT_SCHEME} -derivedDataPath #{OUTPUT_PATH} -parallelizeTargets"
|
||||
WORKSPACE = 'Santa.xcworkspace'
|
||||
DEFAULT_SCHEME = 'All'
|
||||
OUTPUT_PATH = 'Build'
|
||||
DIST_PATH = 'Dist'
|
||||
BINARIES = ['Santa.app', 'santa-driver.kext', 'santad', 'santactl']
|
||||
XCPRETTY_DEFAULTS = '-sc'
|
||||
XCODEBUILD_DEFAULTS = "-workspace #{WORKSPACE} -derivedDataPath #{OUTPUT_PATH} -parallelizeTargets"
|
||||
|
||||
task :default do
|
||||
system("rake -sT")
|
||||
end
|
||||
|
||||
def xctool_available
|
||||
return system 'xctool --version >/dev/null 2>&1'
|
||||
end
|
||||
|
||||
def run_and_output_on_fail(cmd)
|
||||
output=`#{cmd} 2>&1`
|
||||
if not $?.success?
|
||||
raise output
|
||||
end
|
||||
end
|
||||
|
||||
def run_and_output_with_color(cmd)
|
||||
output=`#{cmd} 2>&1`
|
||||
|
||||
has_output = false
|
||||
output.scan(/((Test Suite|Test Case|Executed).*)$/) do |match|
|
||||
has_output = true
|
||||
out = match[0]
|
||||
if out.include?("passed")
|
||||
puts "\e[32m#{out}\e[0m"
|
||||
elsif out.include?("failed")
|
||||
puts "\e[31m#{out}\e[0m"
|
||||
else
|
||||
puts out
|
||||
end
|
||||
end
|
||||
|
||||
if not has_output
|
||||
raise output
|
||||
def xcodebuild(opts)
|
||||
if system "xcodebuild #{XCODEBUILD_DEFAULTS} #{opts} | " \
|
||||
"xcpretty #{XCPRETTY_DEFAULTS} && " \
|
||||
"exit ${PIPESTATUS[0]}"
|
||||
puts "\e[32mPass\e[0m"
|
||||
else
|
||||
raise "\e[31mFail\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -49,6 +27,9 @@ task :init do
|
||||
puts "Pods missing, running 'pod install'"
|
||||
system "pod install" or raise "CocoaPods is not installed. Install with 'sudo gem install cocoapods'"
|
||||
end
|
||||
unless system 'xcpretty -v >/dev/null 2>&1'
|
||||
puts "xcpretty is not installed. Install with 'sudo gem install xcpretty'"
|
||||
end
|
||||
end
|
||||
|
||||
task :remove_existing do
|
||||
@@ -61,7 +42,7 @@ end
|
||||
desc "Clean"
|
||||
task :clean => :init do
|
||||
puts "Cleaning"
|
||||
system "xcodebuild #{XCODE_DEFAULTS} clean"
|
||||
xcodebuild("-scheme All clean")
|
||||
FileUtils.rm_rf(OUTPUT_PATH)
|
||||
FileUtils.rm_rf(DIST_PATH)
|
||||
end
|
||||
@@ -81,11 +62,7 @@ namespace :build do
|
||||
task :build, [:configuration] => :init do |t, args|
|
||||
config = args[:configuration]
|
||||
puts "Building with configuration: #{config}"
|
||||
if xctool_available
|
||||
system "xctool #{XCTOOL_DEFAULTS} -configuration #{config} build"
|
||||
else
|
||||
system "xcodebuild #{XCODE_DEFAULTS} -configuration #{config} build"
|
||||
end
|
||||
xcodebuild("-scheme All -configuration #{config} build")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -145,11 +122,7 @@ namespace :tests do
|
||||
desc "Tests: Logic"
|
||||
task :logic => [:init] do
|
||||
puts "Running logic tests"
|
||||
if xctool_available
|
||||
system "xctool #{XCTOOL_DEFAULTS} test"
|
||||
else
|
||||
system "xcodebuild #{XCODE_DEFAULTS} test"
|
||||
end
|
||||
xcodebuild("-scheme LogicTests test")
|
||||
end
|
||||
|
||||
desc "Tests: Kernel"
|
||||
@@ -178,7 +151,7 @@ end
|
||||
|
||||
task :unload_kext do
|
||||
puts "Unloading kernel extension"
|
||||
system "sudo kextunload /santa-driver.kext 2>/dev/null"
|
||||
system "sudo kextunload -b com.google.santa-driver 2>/dev/null"
|
||||
end
|
||||
|
||||
task :unload_gui do
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
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 */; };
|
||||
@@ -68,7 +69,7 @@
|
||||
0D3AFBF018FB4C6C0087BCEE /* SNTDriverManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */; };
|
||||
0D3AFBF618FB4C7E0087BCEE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D385DB7180DE4A900418BC6 /* Cocoa.framework */; };
|
||||
0D3AFBF818FB4C870087BCEE /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0D416401191974F1006A356A /* SNTCommandSyncStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncStatus.m */; };
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncState.m */; };
|
||||
0D41640519197AD7006A356A /* SNTCommandSyncEventUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D41640419197AD7006A356A /* SNTCommandSyncEventUpload.m */; };
|
||||
0D41DAD41A7C28C800A890FE /* SNTEventTableTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */; };
|
||||
0D42D2B519D1D98A00955F08 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */; };
|
||||
@@ -96,6 +97,10 @@
|
||||
0D7FFD4B1A017D4B00F34435 /* SNTDERDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7FFD4A1A017D4B00F34435 /* SNTDERDecoder.m */; };
|
||||
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
|
||||
0D827E6719DF3C74006EC811 /* SNTCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827E6619DF3C74006EC811 /* SNTCommandStatus.m */; };
|
||||
0D8868091AC48A1100B86659 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */; };
|
||||
0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */; };
|
||||
0D88680C1AC48A1400B86659 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */; };
|
||||
0D88680D1AC48A5D00B86659 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0D8C200C180F359A00CE2BF8 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D8C200B180F359A00CE2BF8 /* Security.framework */; };
|
||||
0D8E18CD19107B56000F89B8 /* SNTDaemonControlController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D8E18CC19107B56000F89B8 /* SNTDaemonControlController.m */; };
|
||||
0D9A7F331759144800035EB5 /* SantaDriver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0D9A7F311759144800035EB5 /* SantaDriver.cc */; };
|
||||
@@ -107,6 +112,7 @@
|
||||
0DA73C9F1934F8100056D7C4 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
|
||||
0DA73CA11934F8100056D7C4 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
|
||||
0DA73CA21934F88D0056D7C4 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
|
||||
0DB390991AB1E11400614002 /* SNTCommandVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB390981AB1E11400614002 /* SNTCommandVersion.m */; };
|
||||
0DB8ACC1185662DC00FEF9C7 /* SNTApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */; };
|
||||
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
@@ -141,6 +147,13 @@
|
||||
0DE50F6C19130358007B2B0C /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
|
||||
0DE50F6E191304E0007B2B0C /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
|
||||
0DE6788D1784A8C2007A9E52 /* SNTExecutionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE6788C1784A8C2007A9E52 /* SNTExecutionController.m */; };
|
||||
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */; };
|
||||
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
0DEFB7C51ACDD80100B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
0DEFB7C61ACDE5F600B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
0DEFB7C81ACF0BFE00B92AAE /* SNTFileWatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */; };
|
||||
0DF395641AB76A7900CBC520 /* NSData+Zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DF395631AB76A7900CBC520 /* NSData+Zlib.m */; };
|
||||
0DF395661AB76ABC00CBC520 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0DF395651AB76ABC00CBC520 /* libz.dylib */; };
|
||||
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 409232791A51B65D00A04527 /* SNTCommandRule.m */; };
|
||||
8BFD9B39112F4D16B3D0EFFB /* libPods-LogicTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */; };
|
||||
E86AE075D7F24FB88FB627C5 /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A84545E322F475FA0B505D5 /* libPods-santad.a */; };
|
||||
@@ -213,6 +226,7 @@
|
||||
0D28E5E119269B3600280F87 /* SNTLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTLogging.h; sourceTree = "<group>"; };
|
||||
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTKernelCommon.h; sourceTree = "<group>"; };
|
||||
0D28E5E41926B55600280F87 /* santactl-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "santactl-Info.plist"; sourceTree = "<group>"; };
|
||||
0D2CD4601A81C7B100C9C910 /* dn.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = dn.plist; sourceTree = "<group>"; };
|
||||
0D35BD9E18FD71CE00921A21 /* santactl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = santactl; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D35BDA118FD71CE00921A21 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "santactl-Prefix.pch"; sourceTree = "<group>"; };
|
||||
@@ -239,8 +253,8 @@
|
||||
0D385DEF180DE51600418BC6 /* SNTNotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTNotificationManager.m; sourceTree = "<group>"; };
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCConnectionTest.m; sourceTree = "<group>"; };
|
||||
0D3AFBF718FB4C870087BCEE /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncStatus.h; sourceTree = "<group>"; };
|
||||
0D416400191974F1006A356A /* SNTCommandSyncStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncStatus.m; sourceTree = "<group>"; };
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncState.h; sourceTree = "<group>"; };
|
||||
0D416400191974F1006A356A /* SNTCommandSyncState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncState.m; sourceTree = "<group>"; };
|
||||
0D41640319197AD7006A356A /* SNTCommandSyncEventUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncEventUpload.h; sourceTree = "<group>"; };
|
||||
0D41640419197AD7006A356A /* SNTCommandSyncEventUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncEventUpload.m; sourceTree = "<group>"; };
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventTableTest.m; sourceTree = "<group>"; };
|
||||
@@ -286,6 +300,7 @@
|
||||
0D9A7F411759330500035EB5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
0DA73C9E1934F8100056D7C4 /* SNTLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTLogging.m; sourceTree = "<group>"; };
|
||||
0DB2B92318085753001C01D9 /* santad-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "santad-Prefix.pch"; sourceTree = "<group>"; };
|
||||
0DB390981AB1E11400614002 /* SNTCommandVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SNTCommandVersion.m; path = version/SNTCommandVersion.m; sourceTree = "<group>"; };
|
||||
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTApplication.h; sourceTree = "<group>"; };
|
||||
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SNTApplication.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
0DB8ACE41858D73000FEF9C7 /* santad-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "santad-Info.plist"; sourceTree = "<group>"; };
|
||||
@@ -315,6 +330,14 @@
|
||||
0DE50F671912716A007B2B0C /* SNTRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTRule.m; sourceTree = "<group>"; };
|
||||
0DE6788B1784A8C2007A9E52 /* SNTExecutionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTExecutionController.h; sourceTree = "<group>"; };
|
||||
0DE6788C1784A8C2007A9E52 /* SNTExecutionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SNTExecutionController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncConstants.m; sourceTree = "<group>"; };
|
||||
0DEFB7C11ACB28BC00B92AAE /* SNTCommandSyncConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncConstants.h; sourceTree = "<group>"; };
|
||||
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTFileWatcher.h; sourceTree = "<group>"; };
|
||||
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcher.m; sourceTree = "<group>"; };
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcherTest.m; sourceTree = "<group>"; };
|
||||
0DF395621AB76A7900CBC520 /* NSData+Zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Zlib.h"; sourceTree = "<group>"; };
|
||||
0DF395631AB76A7900CBC520 /* NSData+Zlib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Zlib.m"; sourceTree = "<group>"; };
|
||||
0DF395651AB76ABC00CBC520 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -347,6 +370,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0DF395661AB76ABC00CBC520 /* libz.dylib in Frameworks */,
|
||||
0DE4C8A118FEF28200466D04 /* Security.framework in Frameworks */,
|
||||
0D35BDBD18FDA23600921A21 /* IOKit.framework in Frameworks */,
|
||||
0D35BD9F18FD71CE00921A21 /* Foundation.framework in Frameworks */,
|
||||
@@ -357,6 +381,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D88680D1AC48A5D00B86659 /* IOKit.framework in Frameworks */,
|
||||
0D6F12D819EC8822006B218E /* SecurityInterface.framework in Frameworks */,
|
||||
0D8C200C180F359A00CE2BF8 /* Security.framework in Frameworks */,
|
||||
0D385DB8180DE4A900418BC6 /* Cocoa.framework in Frameworks */,
|
||||
@@ -395,6 +420,7 @@
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
|
||||
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
|
||||
);
|
||||
path = LogicTests;
|
||||
@@ -403,6 +429,7 @@
|
||||
0D260DB018B68E12002A0B55 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D2CD4601A81C7B100C9C910 /* dn.plist */,
|
||||
0D6FDC8618C6913D0044685C /* apple.pem */,
|
||||
0D6FDC8218C68D7E0044685C /* GIAG2.crt */,
|
||||
0D6FDC8418C68E500044685C /* GIAG2.pem */,
|
||||
@@ -416,14 +443,15 @@
|
||||
0D35BDA018FD71CE00921A21 /* santactl */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
409232751A51914400A04527 /* rule */,
|
||||
0D35BDA118FD71CE00921A21 /* main.m */,
|
||||
0D35BDAA18FD7CFD00921A21 /* SNTCommandController.h */,
|
||||
0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */,
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */,
|
||||
0DE4C8A318FF3AFA00466D04 /* flushcache */,
|
||||
409232751A51914400A04527 /* rule */,
|
||||
0D827E6819DF4F3F006EC811 /* status */,
|
||||
0D35BDB618FD84FC00921A21 /* sync */,
|
||||
0DB390971AB1E0F200614002 /* version */,
|
||||
0D35BDA318FD71CE00921A21 /* Resources */,
|
||||
);
|
||||
name = santactl;
|
||||
@@ -442,9 +470,13 @@
|
||||
0D35BDB618FD84FC00921A21 /* sync */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DF395621AB76A7900CBC520 /* NSData+Zlib.h */,
|
||||
0DF395631AB76A7900CBC520 /* NSData+Zlib.m */,
|
||||
0DCD6060191188B1006B445C /* SNTAuthenticatingURLSession.h */,
|
||||
0DCD6061191188B1006B445C /* SNTAuthenticatingURLSession.m */,
|
||||
0D35BDB418FD84F600921A21 /* SNTCommandSync.m */,
|
||||
0DEFB7C11ACB28BC00B92AAE /* SNTCommandSyncConstants.h */,
|
||||
0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */,
|
||||
0D41640319197AD7006A356A /* SNTCommandSyncEventUpload.h */,
|
||||
0D41640419197AD7006A356A /* SNTCommandSyncEventUpload.m */,
|
||||
0DC5D86F192160180078A5C0 /* SNTCommandSyncLogUpload.h */,
|
||||
@@ -455,8 +487,8 @@
|
||||
0DCD605B19117A90006B445C /* SNTCommandSyncPreflight.m */,
|
||||
0D0A1EC1191998C900B8450F /* SNTCommandSyncRuleDownload.h */,
|
||||
0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */,
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncStatus.h */,
|
||||
0D416400191974F1006A356A /* SNTCommandSyncStatus.m */,
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncState.h */,
|
||||
0D416400191974F1006A356A /* SNTCommandSyncState.m */,
|
||||
0D7FFD491A017D4B00F34435 /* SNTDERDecoder.h */,
|
||||
0D7FFD4A1A017D4B00F34435 /* SNTDERDecoder.m */,
|
||||
);
|
||||
@@ -552,6 +584,7 @@
|
||||
0D91BCB6174E8A7E00131A7D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DF395651AB76ABC00CBC520 /* libz.dylib */,
|
||||
0DCD5F771909C659006B445C /* SecurityInterface.framework */,
|
||||
0D3AFBF718FB4C870087BCEE /* IOKit.framework */,
|
||||
0D8C200B180F359A00CE2BF8 /* Security.framework */,
|
||||
@@ -596,6 +629,8 @@
|
||||
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */,
|
||||
0DCD6040190ACCB8006B445C /* SNTFileInfo.h */,
|
||||
0DCD6041190ACCB8006B445C /* SNTFileInfo.m */,
|
||||
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */,
|
||||
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */,
|
||||
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */,
|
||||
0D28E5E119269B3600280F87 /* SNTLogging.h */,
|
||||
0DA73C9E1934F8100056D7C4 /* SNTLogging.m */,
|
||||
@@ -658,6 +693,14 @@
|
||||
name = DataLayer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DB390971AB1E0F200614002 /* version */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DB390981AB1E11400614002 /* SNTCommandVersion.m */,
|
||||
);
|
||||
name = version;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -863,6 +906,7 @@
|
||||
0D6FDC8518C68E500044685C /* GIAG2.pem in Resources */,
|
||||
0D6FDC8318C68D7E0044685C /* GIAG2.crt in Resources */,
|
||||
0D6F12DA19EDE51E006B218E /* tubitak.crt in Resources */,
|
||||
0D2CD4611A81C7B100C9C910 /* dn.plist in Resources */,
|
||||
0D6FDC8718C6913D0044685C /* apple.pem in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1048,6 +1092,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D88680C1AC48A1400B86659 /* SNTSystemInfo.m in Sources */,
|
||||
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
|
||||
0D3AFBF018FB4C6C0087BCEE /* SNTDriverManager.m in Sources */,
|
||||
0DCD6044190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
@@ -1059,7 +1104,9 @@
|
||||
0DCD604D19105433006B445C /* SNTStoredEvent.m in Sources */,
|
||||
0DCD605819115E57006B445C /* SNTXPCControlInterface.m in Sources */,
|
||||
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
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 */,
|
||||
@@ -1086,6 +1133,7 @@
|
||||
0D35BDC218FDA5D100921A21 /* SNTCodesignChecker.m in Sources */,
|
||||
0D35BDB518FD84F600921A21 /* SNTCommandSync.m in Sources */,
|
||||
0DCD5FBF1909D64A006B445C /* SNTCommandBinaryInfo.m in Sources */,
|
||||
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */,
|
||||
0DCD6062191188B1006B445C /* SNTAuthenticatingURLSession.m in Sources */,
|
||||
0DCD605619115D17006B445C /* SNTXPCControlInterface.m in Sources */,
|
||||
0DE50F6C19130358007B2B0C /* SNTStoredEvent.m in Sources */,
|
||||
@@ -1093,16 +1141,18 @@
|
||||
0DCD605C19117A90006B445C /* SNTCommandSyncPreflight.m in Sources */,
|
||||
0D41640519197AD7006A356A /* SNTCommandSyncEventUpload.m in Sources */,
|
||||
0D42D2B919D2042900955F08 /* SNTConfigurator.m in Sources */,
|
||||
0DF395641AB76A7900CBC520 /* NSData+Zlib.m in Sources */,
|
||||
0D10BE871A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
0DE4C8A618FF3B1700466D04 /* SNTCommandFlushCache.m in Sources */,
|
||||
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncStatus.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */,
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
|
||||
0D35BDA218FD71CE00921A21 /* main.m in Sources */,
|
||||
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 */,
|
||||
0D0A1EC6191AB9B000B8450F /* SNTCommandSyncPostflight.m in Sources */,
|
||||
@@ -1118,6 +1168,7 @@
|
||||
0D54E0B11976F8D3000BB59F /* SNTFileInfo.m in Sources */,
|
||||
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */,
|
||||
0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */,
|
||||
0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */,
|
||||
0DCD605119115A06006B445C /* SNTXPCNotifierInterface.m in Sources */,
|
||||
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */,
|
||||
0D385DF2180DE51600418BC6 /* SNTMessageWindowController.m in Sources */,
|
||||
@@ -1128,6 +1179,7 @@
|
||||
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */,
|
||||
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */,
|
||||
0DA73CA11934F8100056D7C4 /* SNTLogging.m in Sources */,
|
||||
0DEFB7C51ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
|
||||
0D20710E1A7C4A86008B0A9A /* SNTStoredEvent.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1147,6 +1199,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D8868091AC48A1100B86659 /* SNTSystemInfo.m in Sources */,
|
||||
0DE6788D1784A8C2007A9E52 /* SNTExecutionController.m in Sources */,
|
||||
0D10BE861A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
|
||||
@@ -1156,6 +1209,7 @@
|
||||
0D1AF477187C7A2C00D3298D /* SNTCertificate.m in Sources */,
|
||||
0DA73C9F1934F8100056D7C4 /* SNTLogging.m in Sources */,
|
||||
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
|
||||
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */,
|
||||
0D7D01871774F93A005DBAB4 /* SNTDriverManager.m in Sources */,
|
||||
0D8E18CD19107B56000F89B8 /* SNTDaemonControlController.m in Sources */,
|
||||
@@ -1273,7 +1327,6 @@
|
||||
baseConfigurationReference = 13A4FE400F3857C0F5831498 /* Pods-LogicTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Santa.app/Contents/MacOS/Santa";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
@@ -1323,7 +1376,6 @@
|
||||
baseConfigurationReference = BE74E23CF5A553E5F02462B9 /* Pods-LogicTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Santa.app/Contents/MacOS/Santa";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
@@ -1368,6 +1420,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
@@ -1406,6 +1459,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
@@ -1439,6 +1493,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
@@ -1479,6 +1534,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
@@ -1541,6 +1597,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
@@ -1575,6 +1632,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
@@ -1620,6 +1678,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
@@ -1654,6 +1713,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
|
||||
96
Santa.xcodeproj/xcshareddata/xcschemes/LogicTests.xcscheme
Normal file
96
Santa.xcodeproj/xcshareddata/xcschemes/LogicTests.xcscheme
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,12 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6250" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14C1514" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6250"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SNTAboutWindowController">
|
||||
<connections>
|
||||
<outlet property="moreInfoButton" destination="SRu-Kf-vu5" id="Vj2-9Q-05d"/>
|
||||
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -15,7 +16,7 @@
|
||||
<window title="Santa" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="200"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1578"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
@@ -36,19 +37,32 @@
|
||||
<rect key="frame" x="18" y="65" width="444" height="60"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="CcT-ul-1eA">
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="title">Santa is a binary whitelisting system for Mac OS X.
|
||||
<string key="title">Santa is an application whitelisting system for Mac OS X.
|
||||
|
||||
There are no user-configurable settings.</string>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Udo-BY-n7e">
|
||||
<rect key="frame" x="196" y="21" width="88" height="32"/>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SRu-Kf-vu5">
|
||||
<rect key="frame" x="130" y="21" width="111" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="76" id="2Xc-ax-2bV"/>
|
||||
<constraint firstAttribute="width" constant="99" id="JHv-2J-QSe"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uSw-o1-lWW">
|
||||
<buttonCell key="cell" type="push" title="More Info..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6fe-ju-aET">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="openMoreInfoURL:" target="-2" id="dps-TN-rkS"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Udo-BY-n7e">
|
||||
<rect key="frame" x="240" y="21" width="111" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="99" id="2Xc-ax-2bV"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Dismiss" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uSw-o1-lWW">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
@@ -58,10 +72,13 @@ There are no user-configurable settings.</string>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="Udo-BY-n7e" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" priority="900" constant="191" id="1T4-DB-Dz8"/>
|
||||
<constraint firstItem="SRu-Kf-vu5" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="136" id="Ake-nU-qhW"/>
|
||||
<constraint firstItem="BnL-ZS-kXw" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="20" symbolic="YES" id="Fj1-SG-mzF"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Udo-BY-n7e" secondAttribute="bottom" constant="28" id="bpF-hC-haN"/>
|
||||
<constraint firstItem="BnL-ZS-kXw" firstAttribute="centerX" secondItem="Udo-BY-n7e" secondAttribute="centerX" constant="0.5" id="csK-2p-W94"/>
|
||||
<constraint firstAttribute="bottom" secondItem="SRu-Kf-vu5" secondAttribute="bottom" constant="28" id="fCB-02-SEt"/>
|
||||
<constraint firstItem="BnL-ZS-kXw" firstAttribute="centerX" secondItem="se5-gp-TjO" secondAttribute="centerX" id="kez-S0-6Gg"/>
|
||||
<constraint firstItem="Udo-BY-n7e" firstAttribute="leading" secondItem="SRu-Kf-vu5" secondAttribute="trailing" constant="11" id="sYO-yY-w9w"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14C1514" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
|
||||
@@ -7,6 +7,7 @@
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SNTMessageWindowController">
|
||||
<connections>
|
||||
<outlet property="openEventButton" destination="7ua-5a-uSd" id="9s4-ZA-Vlo"/>
|
||||
<outlet property="window" destination="9Bq-yh-54f" id="Uhs-WF-TV9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -57,7 +58,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PXc-xv-A28">
|
||||
<rect key="frame" x="175" y="142" width="304" height="17"/>
|
||||
<rect key="frame" x="175" y="117" width="304" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="300" id="4hh-R2-86s"/>
|
||||
</constraints>
|
||||
@@ -70,45 +71,12 @@
|
||||
<binding destination="-2" name="value" keyPath="self.event.fileSHA256" id="SzX-Ep-rBa"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button toolTip="Show code signing certificate chain" translatesAutoresizingMaskIntoConstraints="NO" id="cJf-k6-OxS" userLabel="Publisher Certs">
|
||||
<rect key="frame" x="340" y="118" width="10" height="15"/>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C3G-wL-u7w">
|
||||
<rect key="frame" x="175" y="142" width="309" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="10" id="QTm-Iv-m5p"/>
|
||||
<constraint firstAttribute="width" constant="305" id="Dem-wH-KHm"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="NSFollowLinkFreestandingTemplate" imagePosition="overlaps" alignment="center" refusesFirstResponder="YES" imageScaling="proportionallyDown" inset="2" id="R72-Qy-Xbb">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="showCertInfo:" target="-2" id="dB0-a3-X31"/>
|
||||
<binding destination="-2" name="hidden" keyPath="self.publisherInfo" id="fFR-f3-Oiw">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSIsNil</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BbV-3h-mmL">
|
||||
<rect key="frame" x="220" y="33" width="110" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="110" id="6Uh-Bd-N64"/>
|
||||
<constraint firstAttribute="height" constant="22" id="GH6-nw-6rD"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="roundTextured" title="OK" bezelStyle="texturedRounded" alignment="center" refusesFirstResponder="YES" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XR6-Xa-gP4">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="closeWindow:" target="-2" id="qQq-gh-8lw"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="C3G-wL-u7w">
|
||||
<rect key="frame" x="175" y="117" width="159" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Code signing information" placeholderString="" id="ztA-La-XgT">
|
||||
<textFieldCell key="cell" selectable="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Code signing information" placeholderString="" id="ztA-La-XgT">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" white="0.0" alpha="0.5" colorSpace="deviceWhite"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -130,7 +98,7 @@ DQ
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lvJ-Rk-UT5">
|
||||
<rect key="frame" x="18" y="117" width="120" height="17"/>
|
||||
<rect key="frame" x="18" y="142" width="120" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Publisher" id="yL9-yD-JXX">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -149,7 +117,7 @@ DQ
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KEB-eH-x2Y">
|
||||
<rect key="frame" x="18" y="142" width="120" height="17"/>
|
||||
<rect key="frame" x="18" y="117" width="120" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="SHA-256" id="eKN-Ic-5zy">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -176,6 +144,60 @@ DQ
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<button toolTip="Show code signing certificate chain" translatesAutoresizingMaskIntoConstraints="NO" id="cJf-k6-OxS" userLabel="Publisher Certs">
|
||||
<rect key="frame" x="51" y="143" width="14" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="14" id="QTm-Iv-m5p"/>
|
||||
<constraint firstAttribute="height" constant="14" id="YwG-0s-jop"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="NSInfo" imagePosition="overlaps" alignment="center" refusesFirstResponder="YES" imageScaling="proportionallyDown" inset="2" id="R72-Qy-Xbb">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="showCertInfo:" target="-2" id="dB0-a3-X31"/>
|
||||
<binding destination="-2" name="hidden" keyPath="self.publisherInfo" id="fFR-f3-Oiw">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSIsNil</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BbV-3h-mmL">
|
||||
<rect key="frame" x="282" y="33" width="110" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="110" id="6Uh-Bd-N64"/>
|
||||
<constraint firstAttribute="height" constant="22" id="GH6-nw-6rD"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="roundTextured" title="Dismiss" bezelStyle="texturedRounded" alignment="center" refusesFirstResponder="YES" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XR6-Xa-gP4">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="closeWindow:" target="-2" id="qQq-gh-8lw"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="7ua-5a-uSd">
|
||||
<rect key="frame" x="158" y="33" width="112" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" priority="900" constant="112" id="Pec-Pa-4aZ"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="roundTextured" title="Open Event..." bezelStyle="texturedRounded" alignment="center" refusesFirstResponder="YES" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="X1b-TF-1TL">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="openEventDetails:" target="-2" id="VhL-ql-rCV"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="bottom" secondItem="4Li-ul-zIi" secondAttribute="bottom" id="1Nc-gl-xMe"/>
|
||||
@@ -183,39 +205,44 @@ DQ
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="leading" secondItem="4Li-ul-zIi" secondAttribute="trailing" constant="20" id="ALv-0v-szi"/>
|
||||
<constraint firstItem="cJf-k6-OxS" firstAttribute="centerY" secondItem="C3G-wL-u7w" secondAttribute="centerY" id="FdL-ZZ-Vbe"/>
|
||||
<constraint firstItem="t8c-Fx-e5h" firstAttribute="top" secondItem="Iwq-Lx-rLv" secondAttribute="top" constant="30" id="FuB-GX-0jg"/>
|
||||
<constraint firstItem="lvJ-Rk-UT5" firstAttribute="leading" secondItem="cJf-k6-OxS" secondAttribute="trailing" constant="-45" id="GD2-Ka-deo"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="centerY" secondItem="oFj-ol-xpL" secondAttribute="centerY" id="GXI-pT-FM1"/>
|
||||
<constraint firstItem="oFj-ol-xpL" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="20" id="IwX-ja-ZIs"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="centerY" secondItem="d9e-Wv-Y5H" secondAttribute="centerY" id="JeD-9X-ULA"/>
|
||||
<constraint firstItem="oFj-ol-xpL" firstAttribute="leading" secondItem="d9e-Wv-Y5H" secondAttribute="leading" priority="999" id="MVr-jY-GDj"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="top" secondItem="cD5-Su-lXR" secondAttribute="bottom" constant="30" id="Nsl-zf-poH"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="leading" secondItem="4Li-ul-zIi" secondAttribute="trailing" constant="20" id="SCl-Ky-VmT"/>
|
||||
<constraint firstItem="7ua-5a-uSd" firstAttribute="top" secondItem="oFj-ol-xpL" secondAttribute="bottom" constant="35" id="Scq-zQ-Sao"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="KEB-eH-x2Y" secondAttribute="trailing" constant="20" id="Seb-c0-MUL"/>
|
||||
<constraint firstAttribute="centerX" secondItem="cD5-Su-lXR" secondAttribute="centerX" id="V0a-Py-iEc"/>
|
||||
<constraint firstItem="oFj-ol-xpL" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="leading" priority="999" id="Z6G-l9-G4a"/>
|
||||
<constraint firstAttribute="centerX" secondItem="BbV-3h-mmL" secondAttribute="centerX" id="acs-5J-vQY"/>
|
||||
<constraint firstAttribute="centerX" secondItem="BbV-3h-mmL" secondAttribute="centerX" priority="900" id="acs-5J-vQY"/>
|
||||
<constraint firstItem="KEB-eH-x2Y" firstAttribute="leading" secondItem="oFj-ol-xpL" secondAttribute="leading" priority="999" id="b5A-M7-ZsD"/>
|
||||
<constraint firstItem="KEB-eH-x2Y" firstAttribute="centerY" secondItem="PXc-xv-A28" secondAttribute="centerY" id="cHe-pZ-0Oq"/>
|
||||
<constraint firstItem="cD5-Su-lXR" firstAttribute="top" secondItem="t8c-Fx-e5h" secondAttribute="bottom" constant="30" id="dYg-zP-wh2"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="leading" secondItem="4Li-ul-zIi" secondAttribute="trailing" constant="20" id="eSz-lz-Fdh"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="top" secondItem="pc8-G9-4pJ" secondAttribute="top" id="fzY-94-y2n"/>
|
||||
<constraint firstAttribute="centerX" secondItem="t8c-Fx-e5h" secondAttribute="centerX" constant="-0.5" id="h3d-Kc-q88"/>
|
||||
<constraint firstItem="BbV-3h-mmL" firstAttribute="leading" secondItem="7ua-5a-uSd" secondAttribute="trailing" constant="12" id="ioO-NJ-Jqo"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="centerY" secondItem="lvJ-Rk-UT5" secondAttribute="centerY" id="jfs-YI-7Ae"/>
|
||||
<constraint firstItem="lvJ-Rk-UT5" firstAttribute="trailing" secondItem="KEB-eH-x2Y" secondAttribute="trailing" id="jlD-Lo-abc"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="oFj-ol-xpL" secondAttribute="trailing" constant="20" id="kOG-Cj-hFG"/>
|
||||
<constraint firstItem="oFj-ol-xpL" firstAttribute="trailing" secondItem="lvJ-Rk-UT5" secondAttribute="trailing" id="lse-kg-lA2"/>
|
||||
<constraint firstItem="d9e-Wv-Y5H" firstAttribute="trailing" secondItem="KEB-eH-x2Y" secondAttribute="trailing" id="pdq-a6-Y73"/>
|
||||
<constraint firstAttribute="centerX" secondItem="7ua-5a-uSd" secondAttribute="centerX" constant="61" id="phL-j9-rPq"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="trailing" constant="20" id="qKi-KT-jzJ"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="top" secondItem="C3G-wL-u7w" secondAttribute="bottom" constant="8" id="rwU-fp-qh6"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="top" secondItem="C3G-wL-u7w" secondAttribute="bottom" constant="8" id="sG1-gQ-Qoo"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="top" secondItem="PXc-xv-A28" secondAttribute="bottom" constant="8" id="snd-8T-LjC"/>
|
||||
<constraint firstItem="PXc-xv-A28" firstAttribute="bottom" secondItem="h6f-PY-cc0" secondAttribute="top" constant="-8" id="sG1-gQ-Qoo"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="bottom" secondItem="PXc-xv-A28" secondAttribute="top" constant="-8" id="snd-8T-LjC"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="d9e-Wv-Y5H" secondAttribute="trailing" constant="20" id="stz-Vm-Kxo"/>
|
||||
<constraint firstItem="PXc-xv-A28" firstAttribute="leading" secondItem="4Li-ul-zIi" secondAttribute="trailing" constant="20" id="tAa-1s-xVZ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="BbV-3h-mmL" secondAttribute="bottom" constant="35" id="ukF-FH-DE8"/>
|
||||
<constraint firstItem="cJf-k6-OxS" firstAttribute="leading" secondItem="C3G-wL-u7w" secondAttribute="trailing" constant="8" id="wsf-ru-MoA"/>
|
||||
<constraint firstItem="PXc-xv-A28" firstAttribute="top" secondItem="pc8-G9-4pJ" secondAttribute="bottom" constant="8" id="zst-nc-VqA"/>
|
||||
<constraint firstItem="d9e-Wv-Y5H" firstAttribute="baseline" secondItem="pc8-G9-4pJ" secondAttribute="baseline" id="xGd-Xr-3Z0"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="bottom" secondItem="C3G-wL-u7w" secondAttribute="top" constant="-8" id="zst-nc-VqA"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<point key="canvasLocation" x="162" y="710.5"/>
|
||||
<point key="canvasLocation" x="113" y="777.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSFollowLinkFreestandingTemplate" width="14" height="14"/>
|
||||
<image name="NSInfo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -14,4 +14,8 @@
|
||||
|
||||
@interface SNTAboutWindowController : NSWindowController
|
||||
|
||||
@property IBOutlet NSButton *moreInfoButton;
|
||||
|
||||
- (IBAction)openMoreInfoURL:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,10 +14,24 @@
|
||||
|
||||
#import "SNTAboutWindowController.h"
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
@implementation SNTAboutWindowController
|
||||
|
||||
- (instancetype)init {
|
||||
return [super initWithWindowNibName:@"AboutWindow"];
|
||||
}
|
||||
|
||||
- (void)loadWindow {
|
||||
[super loadWindow];
|
||||
if (![[SNTConfigurator configurator] moreInfoURL]) {
|
||||
[self.moreInfoButton removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)openMoreInfoURL:(id)sender {
|
||||
[[NSWorkspace sharedWorkspace] openURL:[[SNTConfigurator configurator] moreInfoURL]];
|
||||
[self close];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
#import "SNTAppDelegate.h"
|
||||
|
||||
#import "SNTAboutWindowController.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileWatcher.h"
|
||||
#import "SNTNotificationManager.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
|
||||
@interface SNTAppDelegate ()
|
||||
@property SNTAboutWindowController *aboutWindowController;
|
||||
@property SNTFileWatcher *configFileWatcher;
|
||||
@property SNTNotificationManager *notificationManager;
|
||||
@property SNTXPCConnection *listener;
|
||||
@end
|
||||
@@ -30,6 +33,12 @@
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
[self setupMenu];
|
||||
|
||||
self.configFileWatcher = [[SNTFileWatcher alloc] initWithFilePath:kDefaultConfigFilePath
|
||||
handler:^{
|
||||
[[SNTConfigurator configurator] reloadConfigData];
|
||||
}];
|
||||
|
||||
self.aboutWindowController = [[SNTAboutWindowController alloc] init];
|
||||
self.notificationManager = [[SNTNotificationManager alloc] init];
|
||||
|
||||
@@ -56,9 +65,8 @@
|
||||
- (void)createConnection {
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
self.listener =
|
||||
[[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId]
|
||||
options:NSXPCConnectionPrivileged];
|
||||
self.listener = [[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId]
|
||||
options:NSXPCConnectionPrivileged];
|
||||
self.listener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
|
||||
self.listener.exportedObject = self.notificationManager;
|
||||
self.listener.rejectedHandler = ^{
|
||||
@@ -73,7 +81,6 @@
|
||||
self.listener.invalidationHandler = nil;
|
||||
[self.listener invalidate];
|
||||
self.listener = nil;
|
||||
NSLog(@"KILLING CONNECTION");
|
||||
}
|
||||
|
||||
- (void)attemptReconnection {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
- (IBAction)fadeIn:(id)sender {
|
||||
[self setAlphaValue:0.f];
|
||||
[self center];
|
||||
[self makeKeyAndOrderFront:sender];
|
||||
[NSAnimationContext beginGrouping];
|
||||
[[NSAnimationContext currentContext] setDuration:0.15f];
|
||||
|
||||
@@ -47,11 +47,17 @@
|
||||
///
|
||||
/// A 'friendly' string representing the certificate information
|
||||
///
|
||||
@property(readonly) IBOutlet NSString *publisherInfo;
|
||||
@property(readonly) NSString *publisherInfo;
|
||||
|
||||
///
|
||||
/// An optional message to display with this block.
|
||||
///
|
||||
@property(readonly) IBOutlet NSAttributedString *attributedCustomMessage;
|
||||
@property(readonly) NSAttributedString *attributedCustomMessage;
|
||||
|
||||
///
|
||||
/// Reference to the "Open Event" button in the XIB. Used to either remove the button
|
||||
/// if it isn't needed or set its title if it is.
|
||||
///
|
||||
@property IBOutlet NSButton *openEventButton;
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#import <SecurityInterface/SFCertificatePanel.h>
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTMessageWindow.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
@@ -27,14 +28,26 @@
|
||||
self = [super initWithWindowNibName:@"MessageWindow"];
|
||||
if (self) {
|
||||
_event = event;
|
||||
_customMessage = message;
|
||||
[self.window setMovableByWindowBackground:NO];
|
||||
[self.window setLevel:NSPopUpMenuWindowLevel];
|
||||
[self.window center];
|
||||
_customMessage = (message != (NSString *)[NSNull null] ? message : nil);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadWindow {
|
||||
[super loadWindow];
|
||||
[self.window setLevel:NSPopUpMenuWindowLevel];
|
||||
[self.window setMovableByWindowBackground:YES];
|
||||
|
||||
if (![[SNTConfigurator configurator] eventDetailURL]) {
|
||||
[self.openEventButton removeFromSuperview];
|
||||
} else {
|
||||
NSString *eventDetailText = [[SNTConfigurator configurator] eventDetailText];
|
||||
if (eventDetailText) {
|
||||
[self.openEventButton setTitle:eventDetailText];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)showWindow:(id)sender {
|
||||
[(SNTMessageWindow *)self.window fadeIn:sender];
|
||||
}
|
||||
@@ -62,10 +75,25 @@
|
||||
showGroup:YES];
|
||||
}
|
||||
|
||||
- (IBAction)openEventDetails:(id)sender {
|
||||
SNTConfigurator *config = [SNTConfigurator configurator];
|
||||
|
||||
NSString *formatStr = config.eventDetailURL;
|
||||
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%file_sha%"
|
||||
withString:self.event.fileSHA256];
|
||||
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%username%"
|
||||
withString:self.event.executingUser];
|
||||
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%machine_id%"
|
||||
withString:config.machineID];
|
||||
|
||||
[self closeWindow:sender];
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:formatStr]];
|
||||
}
|
||||
|
||||
#pragma mark Generated properties
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
|
||||
if (! [key isEqualToString:@"event"]) {
|
||||
if (![key isEqualToString:@"event"]) {
|
||||
return [NSSet setWithObject:@"event"];
|
||||
} else {
|
||||
return nil;
|
||||
@@ -98,7 +126,7 @@
|
||||
NSString *htmlFooter = @"</body></html>";
|
||||
|
||||
NSString *message;
|
||||
if (self.customMessage && ![self.customMessage isEqual:@""]) {
|
||||
if ([self.customMessage length] > 0) {
|
||||
message = self.customMessage;
|
||||
} else {
|
||||
message = @"The following application has been blocked from executing<br />"
|
||||
@@ -111,7 +139,6 @@
|
||||
NSAttributedString *returnStr = [[NSAttributedString alloc] initWithHTML:htmlData
|
||||
documentAttributes:NULL];
|
||||
return returnStr;
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -54,9 +54,16 @@
|
||||
|
||||
- (void)postBlockNotification:(SNTStoredEvent *)event withCustomMessage:(NSString *)message {
|
||||
// See if this binary is already in the list of pending notifications.
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"fileSHA256==%@", event.fileSHA256];
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"event.fileSHA256==%@",
|
||||
event.fileSHA256];
|
||||
if ([[self.pendingNotifications filteredArrayUsingPredicate:predicate] count]) return;
|
||||
|
||||
if (!event) {
|
||||
NSLog(@"Error: Missing event object in message received from daemon!");
|
||||
return;
|
||||
}
|
||||
if (!message) message = (NSString *)[NSNull null];
|
||||
|
||||
// Notifications arrive on a background thread but UI updates must happen on the main thread.
|
||||
// This includes making windows.
|
||||
[self performSelectorOnMainThread:@selector(postBlockNotificationMainThread:)
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#import <Security/Security.h>
|
||||
|
||||
@interface SNTCertificate ()
|
||||
///
|
||||
/// A container for cached property values
|
||||
///
|
||||
@property NSMutableDictionary *memoizedData;
|
||||
@end
|
||||
|
||||
@@ -46,7 +44,8 @@ static NSString *const kCertDataKey = @"certData";
|
||||
// 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.
|
||||
// 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];
|
||||
|
||||
@@ -16,31 +16,70 @@
|
||||
|
||||
///
|
||||
/// Singleton that provides an interface for managing configuration values on disk
|
||||
/// @note This class is designed as a singleton but that is not enforced.
|
||||
/// @note This class is designed as a singleton but that is not strictly enforced.
|
||||
///
|
||||
@interface SNTConfigurator : NSObject
|
||||
|
||||
/// Default config file path
|
||||
extern NSString * const kDefaultConfigFilePath;
|
||||
|
||||
#pragma mark - Daemon Settings
|
||||
|
||||
///
|
||||
/// The operating mode
|
||||
/// The operating mode.
|
||||
///
|
||||
@property santa_clientmode_t clientMode;
|
||||
|
||||
///
|
||||
/// Whether or not to log all events, even for whitelisted binaries.
|
||||
///
|
||||
@property BOOL logAllEvents;
|
||||
|
||||
# pragma mark - GUI Settings
|
||||
|
||||
///
|
||||
/// The URL to open when the user clicks "More Info..." when opening Santa.app.
|
||||
/// If unset, the button will not be displayed.
|
||||
///
|
||||
@property(readonly) NSURL *moreInfoURL;
|
||||
|
||||
///
|
||||
/// When the user gets a block notification, a button can be displayed which will
|
||||
/// take them to a web page with more information about that event.
|
||||
/// This property contains a kind of format string to be turned into the URL to send them to.
|
||||
/// The following sequences will be replaced in the final URL:
|
||||
///
|
||||
/// %file_sha% -- SHA-256 of the file that was blocked.
|
||||
/// %machine_id% -- ID of the machine.
|
||||
/// %username% -- executing user.
|
||||
///
|
||||
/// @note: This is not an NSURL because the format-string parsing is done elsewhere.
|
||||
///
|
||||
/// If this item isn't set, the Open Event button will not be displayed.
|
||||
///
|
||||
@property(readonly) NSString *eventDetailURL;
|
||||
|
||||
///
|
||||
/// Related to the above property, this string represents the text to show on the button.
|
||||
///
|
||||
@property(readonly) NSString *eventDetailText;
|
||||
|
||||
# pragma mark - Sync Settings
|
||||
|
||||
///
|
||||
/// The base URL of the sync server
|
||||
/// The base URL of the sync server.
|
||||
///
|
||||
@property(readonly) NSURL *syncBaseURL;
|
||||
|
||||
///
|
||||
/// The machine owner
|
||||
/// The machine owner.
|
||||
///
|
||||
@property(readonly) NSString *machineOwner;
|
||||
|
||||
///
|
||||
/// If set, this over-rides the default machine ID used for syncing
|
||||
/// If set, this over-rides the default machine ID used for syncing.
|
||||
///
|
||||
@property(readonly) NSString *machineIDOverride;
|
||||
@property(readonly) NSString *machineID;
|
||||
|
||||
# pragma mark Server Auth Settings
|
||||
|
||||
@@ -80,15 +119,20 @@
|
||||
@property(readonly) NSString *syncClientAuthCertificateIssuer;
|
||||
|
||||
///
|
||||
/// Retrieve an initialized singleton configurator object using the default file path
|
||||
/// Retrieve an initialized singleton configurator object using the default file path.
|
||||
///
|
||||
+ (instancetype)configurator;
|
||||
|
||||
///
|
||||
/// Designated initializer
|
||||
/// Designated initializer.
|
||||
///
|
||||
/// @param filePath The path to the file to use as a backing store.
|
||||
///
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath;
|
||||
|
||||
///
|
||||
/// Re-read config data from disk.
|
||||
///
|
||||
- (void)reloadConfigData;
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
|
||||
@interface SNTConfigurator ()
|
||||
@property NSString *configFilePath;
|
||||
@@ -24,9 +25,17 @@
|
||||
@implementation SNTConfigurator
|
||||
|
||||
/// The hard-coded path to the config file
|
||||
static NSString * const kConfigFilePath = @"/var/db/santa/config.plist";
|
||||
NSString * const kDefaultConfigFilePath = @"/var/db/santa/config.plist";
|
||||
|
||||
/// The keys in the config file
|
||||
static NSString * const kClientModeKey = @"ClientMode";
|
||||
|
||||
static NSString * const kLogAllEventsKey = @"LogAllEvents";
|
||||
|
||||
static NSString * const kMoreInfoURLKey = @"MoreInfoURL";
|
||||
static NSString * const kEventDetailURLKey = @"EventDetailURL";
|
||||
static NSString * const kEventDetailTextKey = @"EventDetailText";
|
||||
|
||||
static NSString * const kSyncBaseURLKey = @"SyncBaseURL";
|
||||
static NSString * const kClientAuthCertificateFileKey = @"ClientAuthCertificateFile";
|
||||
static NSString * const kClientAuthCertificatePasswordKey = @"ClientAuthCertificatePassword";
|
||||
@@ -34,7 +43,6 @@ static NSString * const kClientAuthCertificateCNKey = @"ClientAuthCertificateCN"
|
||||
static NSString * const kClientAuthCertificateIssuerKey = @"ClientAuthCertificateIssuerCN";
|
||||
static NSString * const kServerAuthRootsDataKey = @"ServerAuthRootsData";
|
||||
static NSString * const kServerAuthRootsFileKey = @"ServerAuthRootsFile";
|
||||
static NSString * const kClientModeKey = @"ClientMode";
|
||||
|
||||
static NSString * const kMachineOwnerKey = @"MachineOwner";
|
||||
static NSString * const kMachineIDKey = @"MachineID";
|
||||
@@ -60,13 +68,51 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
static SNTConfigurator *sharedConfigurator = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedConfigurator = [[SNTConfigurator alloc] initWithFilePath:kConfigFilePath];
|
||||
sharedConfigurator = [[SNTConfigurator alloc] initWithFilePath:kDefaultConfigFilePath];
|
||||
});
|
||||
return sharedConfigurator;
|
||||
}
|
||||
|
||||
# pragma mark Public Interface
|
||||
|
||||
- (santa_clientmode_t)clientMode {
|
||||
int cm = [self.configData[kClientModeKey] intValue];
|
||||
if (cm > CLIENTMODE_UNKNOWN && cm < CLIENTMODE_MAX) {
|
||||
return cm;
|
||||
} else {
|
||||
self.configData[kClientModeKey] = @(CLIENTMODE_MONITOR);
|
||||
return CLIENTMODE_MONITOR;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setClientMode:(santa_clientmode_t)newMode {
|
||||
if (newMode > CLIENTMODE_UNKNOWN && newMode < CLIENTMODE_MAX) {
|
||||
self.configData[kClientModeKey] = @(newMode);
|
||||
[self saveConfigToDisk];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)logAllEvents {
|
||||
return [self.configData[kLogAllEventsKey] boolValue];
|
||||
}
|
||||
|
||||
- (void)setLogAllEvents:(BOOL)logAllEvents {
|
||||
self.configData[kLogAllEventsKey] = @(logAllEvents);
|
||||
[self saveConfigToDisk];
|
||||
}
|
||||
|
||||
- (NSURL *)moreInfoURL {
|
||||
return [NSURL URLWithString:self.configData[kMoreInfoURLKey]];
|
||||
}
|
||||
|
||||
- (NSString *)eventDetailURL {
|
||||
return self.configData[kEventDetailURLKey];
|
||||
}
|
||||
|
||||
- (NSString *)eventDetailText {
|
||||
return self.configData[kEventDetailTextKey];
|
||||
}
|
||||
|
||||
- (NSURL *)syncBaseURL {
|
||||
return [NSURL URLWithString:self.configData[kSyncBaseURLKey]];
|
||||
}
|
||||
@@ -96,92 +142,55 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
}
|
||||
|
||||
- (NSString *)machineOwner {
|
||||
NSString *machineOwner;
|
||||
|
||||
if (self.configData[kMachineOwnerPlistFileKey] && self.configData[kMachineOwnerPlistKeyKey]) {
|
||||
NSDictionary *plist =
|
||||
[NSDictionary dictionaryWithContentsOfFile:self.configData[kMachineOwnerPlistFileKey]];
|
||||
return plist[kMachineOwnerPlistKeyKey];
|
||||
machineOwner = plist[self.configData[kMachineOwnerPlistKeyKey]];
|
||||
}
|
||||
|
||||
if (self.configData[kMachineOwnerKey]) {
|
||||
return self.configData[kMachineOwnerKey];
|
||||
machineOwner = self.configData[kMachineOwnerKey];
|
||||
}
|
||||
|
||||
return @"";
|
||||
if (!machineOwner) machineOwner = @"";
|
||||
|
||||
return machineOwner;
|
||||
}
|
||||
|
||||
- (NSString *)machineIDOverride {
|
||||
- (NSString *)machineID {
|
||||
NSString *machineId;
|
||||
|
||||
if (self.configData[kMachineIDPlistFileKey] && self.configData[kMachineIDPlistKeyKey]) {
|
||||
NSDictionary *plist =
|
||||
[NSDictionary dictionaryWithContentsOfFile:self.configData[kMachineIDPlistFileKey]];
|
||||
return plist[kMachineIDPlistKeyKey];
|
||||
machineId = plist[self.configData[kMachineIDPlistKeyKey]];
|
||||
}
|
||||
|
||||
if (self.configData[kMachineIDKey]) {
|
||||
return self.configData[kMachineIDKey];
|
||||
machineId = self.configData[kMachineIDKey];
|
||||
}
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (santa_clientmode_t)clientMode {
|
||||
int cm = [self.configData[kClientModeKey] intValue];
|
||||
if (cm > CLIENTMODE_UNKNOWN && cm < CLIENTMODE_MAX) {
|
||||
return cm;
|
||||
} else {
|
||||
self.configData[kClientModeKey] = @(CLIENTMODE_MONITOR);
|
||||
return CLIENTMODE_MONITOR;
|
||||
if ([machineId length] == 0) {
|
||||
machineId = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
- (void)setClientMode:(santa_clientmode_t)newMode {
|
||||
if (newMode > CLIENTMODE_UNKNOWN && newMode < CLIENTMODE_MAX) {
|
||||
[self reloadConfigData];
|
||||
self.configData[kClientModeKey] = @(newMode);
|
||||
[self saveConfigToDisk];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
///
|
||||
/// Saves the current @c _configData to disk.
|
||||
///
|
||||
- (void)saveConfigToDisk {
|
||||
[self.configData writeToFile:kConfigFilePath atomically:YES];
|
||||
}
|
||||
|
||||
///
|
||||
/// Populate @c self.configData, using the config file on disk if possible,
|
||||
/// otherwise an empty mutable dictionary.
|
||||
///
|
||||
/// If the config file's permissions are not @c 0644, will attempt to set them
|
||||
/// but will fail silently if this cannot be done.
|
||||
///
|
||||
- (void)reloadConfigData {
|
||||
if (!self.configData) self.configData = [NSMutableDictionary dictionary];
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
if (![fm fileExistsAtPath:self.configFilePath]) {
|
||||
_configData = [NSMutableDictionary dictionary];
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the config file permissions are 0644. Fail silently if they can't be changed.
|
||||
NSDictionary *fileAttrs = [fm attributesOfItemAtPath:self.configFilePath error:nil];
|
||||
if ([fileAttrs filePosixPermissions] != 0644) {
|
||||
[fm setAttributes:@{ NSFilePosixPermissions: @(0644) }
|
||||
ofItemAtPath:self.configFilePath
|
||||
error:nil];
|
||||
}
|
||||
if (![fm fileExistsAtPath:self.configFilePath]) return;
|
||||
|
||||
NSError *error;
|
||||
NSData *readData = [NSData dataWithContentsOfFile:self.configFilePath
|
||||
options:NSDataReadingMappedIfSafe
|
||||
error:&error];
|
||||
if (error) {
|
||||
fprintf(stderr, "%s\n", [[NSString stringWithFormat:@"Could not read configuration file %@: %@",
|
||||
self.configFilePath, [error localizedDescription]] UTF8String]);
|
||||
|
||||
_configData = [NSMutableDictionary dictionary];
|
||||
LOGE(@"Could not read configuration file: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -191,16 +200,30 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
format:NULL
|
||||
error:&error];
|
||||
if (error) {
|
||||
fprintf(stderr, "%s\n",
|
||||
[[NSString stringWithFormat:@"Could not parse configuration file %@: %@",
|
||||
self.configFilePath,
|
||||
[error localizedDescription]] UTF8String]);
|
||||
|
||||
_configData = [NSMutableDictionary dictionary];
|
||||
LOGE(@"Could not parse configuration file: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
_configData = [configData mutableCopy];
|
||||
// Ensure no-one is trying to change the client mode behind Santa's back.
|
||||
if (self.configData[kClientModeKey] && configData[kClientModeKey] &&
|
||||
![self.configData[kClientModeKey] isEqual:configData[kClientModeKey]] &&
|
||||
geteuid() == 0) {
|
||||
NSMutableDictionary *configDataMutable = [configData mutableCopy];
|
||||
configDataMutable[kClientModeKey] = self.configData[kClientModeKey];
|
||||
self.configData = configDataMutable;
|
||||
[self saveConfigToDisk];
|
||||
} else {
|
||||
self.configData = [configData mutableCopy];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
///
|
||||
/// Saves the current @c self.configData to disk.
|
||||
///
|
||||
- (void)saveConfigToDisk {
|
||||
[self.configData writeToFile:self.configFilePath atomically:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
34
Source/common/SNTFileWatcher.h
Normal file
34
Source/common/SNTFileWatcher.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/// 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.
|
||||
|
||||
///
|
||||
/// Simple file watching class using dispatch sources. Will automatically
|
||||
/// reload the watch if the file is deleted. Will continue watching for
|
||||
/// events until deallocated.
|
||||
///
|
||||
@interface SNTFileWatcher : NSObject
|
||||
|
||||
///
|
||||
/// Designated initializer
|
||||
/// Initializes the watcher and begins watching for modifications.
|
||||
///
|
||||
/// @param filePath the file to watch.
|
||||
/// @param handler the handler to call when changes happen.
|
||||
///
|
||||
/// @note Shortly after the file has been opened and monitoring has begun, the provided handler
|
||||
/// will be called.
|
||||
///
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath handler:(void (^)(void))handler;
|
||||
|
||||
@end
|
||||
102
Source/common/SNTFileWatcher.m
Normal file
102
Source/common/SNTFileWatcher.m
Normal file
@@ -0,0 +1,102 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "SNTFileWatcher.h"
|
||||
|
||||
@interface SNTFileWatcher ()
|
||||
@property NSString *filePath;
|
||||
@property dispatch_source_t monitoringSource;
|
||||
|
||||
@property(strong) void (^eventHandler)(void);
|
||||
@property(strong) void (^internalEventHandler)(void);
|
||||
@property(strong) void (^internalCancelHandler)(void);
|
||||
@end
|
||||
|
||||
@implementation SNTFileWatcher
|
||||
|
||||
- (instancetype)init {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath handler:(void (^)(void))handler {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_filePath = filePath;
|
||||
_eventHandler = handler;
|
||||
|
||||
if (!_filePath || !_eventHandler) return nil;
|
||||
|
||||
[self beginWatchingFile];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self stopWatchingFile];
|
||||
}
|
||||
|
||||
- (void)beginWatchingFile {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
int mask = (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE |
|
||||
DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_RENAME);
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
|
||||
|
||||
self.internalEventHandler = ^{
|
||||
unsigned long l = dispatch_source_get_data(weakSelf.monitoringSource);
|
||||
if (l & DISPATCH_VNODE_DELETE || l & DISPATCH_VNODE_RENAME) {
|
||||
if (weakSelf.monitoringSource) dispatch_source_cancel(weakSelf.monitoringSource);
|
||||
} else {
|
||||
weakSelf.eventHandler();
|
||||
}
|
||||
};
|
||||
|
||||
self.internalCancelHandler = ^{
|
||||
int fd;
|
||||
|
||||
if (weakSelf.monitoringSource) {
|
||||
fd = (int)dispatch_source_get_handle(weakSelf.monitoringSource);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
while ((fd = open([weakSelf.filePath fileSystemRepresentation], O_EVTONLY)) < 0) {
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
weakSelf.monitoringSource = dispatch_source_create(
|
||||
DISPATCH_SOURCE_TYPE_VNODE, fd, mask, queue);
|
||||
dispatch_source_set_event_handler(weakSelf.monitoringSource, weakSelf.internalEventHandler);
|
||||
dispatch_source_set_cancel_handler(weakSelf.monitoringSource, weakSelf.internalCancelHandler);
|
||||
dispatch_resume(weakSelf.monitoringSource);
|
||||
|
||||
weakSelf.eventHandler();
|
||||
};
|
||||
|
||||
dispatch_async(queue, self.internalCancelHandler);
|
||||
}
|
||||
|
||||
- (void)stopWatchingFile {
|
||||
if (!self.monitoringSource) return;
|
||||
|
||||
int fd = (int)dispatch_source_get_handle(self.monitoringSource);
|
||||
dispatch_source_set_event_handler_f(self.monitoringSource, NULL);
|
||||
dispatch_source_set_cancel_handler(self.monitoringSource, ^{
|
||||
close(fd);
|
||||
});
|
||||
|
||||
dispatch_source_cancel(self.monitoringSource);
|
||||
self.monitoringSource = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -58,6 +58,6 @@ void logMessage(int level, FILE *destination, NSString *format, ...) {
|
||||
}
|
||||
|
||||
fprintf(destination, "%s\n", [[NSString stringWithFormat:@"[%@] %@ %@: %@",
|
||||
[dateFormatter stringFromDate:[NSDate date]], levelName, binaryName, s] UTF8String]);
|
||||
[dateFormatter stringFromDate:[NSDate date]], levelName, binaryName, s] UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,4 +90,9 @@
|
||||
///
|
||||
@property NSNumber *pid;
|
||||
|
||||
///
|
||||
/// The parent process ID of the binary being executed.
|
||||
///
|
||||
@property NSNumber *ppid;
|
||||
|
||||
@end
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
ENCODE(self.executingUser, @"executingUser");
|
||||
ENCODE(self.occurrenceDate, @"occurrenceDate");
|
||||
ENCODE(@(self.decision), @"decision");
|
||||
ENCODE(self.pid, @"pid");
|
||||
ENCODE(self.ppid, @"ppid");
|
||||
|
||||
ENCODE(self.loggedInUsers, @"loggedInUsers");
|
||||
ENCODE(self.currentSessions, @"currentSessions");
|
||||
@@ -63,6 +65,8 @@
|
||||
_executingUser = DECODE(NSString, @"executingUser");
|
||||
_occurrenceDate = DECODE(NSDate, @"occurrenceDate");
|
||||
_decision = [DECODE(NSNumber, @"decision") intValue];
|
||||
_pid = DECODE(NSNumber, @"pid");
|
||||
_ppid = DECODE(NSNumber, @"ppid");
|
||||
|
||||
_loggedInUsers = DECODEARRAY(NSString, @"loggedInUsers");
|
||||
_currentSessions = DECODEARRAY(NSString, @"currentSessions");
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
CFSTR(kIOPlatformSerialNumberKey),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
|
||||
|
||||
IOObjectRelease(platformExpert);
|
||||
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
}
|
||||
|
||||
+ (NSString *)longHostname {
|
||||
return [[NSHost currentHost] name];
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
gethostname(hostname, (int)sizeof(hostname));
|
||||
return @(hostname);
|
||||
}
|
||||
|
||||
# pragma mark - Internal
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
for (int sleepLoops = 0; sleepLoops < 1000 && !verificationComplete; sleepLoops++) {
|
||||
usleep(5000);
|
||||
}
|
||||
if (!verificationComplete) [self invalidate];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
/// Database ops
|
||||
///
|
||||
- (void)databaseRuleCounts:(void (^)(uint64_t binary, uint64_t certificate))reply;
|
||||
- (void)databaseRuleAddRule:(SNTRule *)rule withReply:(void (^)())reply;
|
||||
- (void)databaseRuleAddRules:(NSArray *)rules withReply:(void (^)())reply;
|
||||
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
|
||||
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
|
||||
|
||||
- (void)databaseEventCount:(void (^)(uint64_t count))reply;
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 withReply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 reply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventsPending:(void (^)(NSArray *events))reply;
|
||||
- (void)databaseRemoveEventsWithIDs:(NSArray *)ids;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
/// Misc ops
|
||||
///
|
||||
- (void)clientMode:(void (^)(santa_clientmode_t))reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode withReply:(void (^)())reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode reply:(void (^)())reply;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
ofReply:YES];
|
||||
|
||||
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTRule class], nil]
|
||||
forSelector:@selector(databaseRuleAddRules:withReply:)
|
||||
forSelector:@selector(databaseRuleAddRules:cleanSlate:reply:)
|
||||
argumentIndex:0
|
||||
ofReply:NO];
|
||||
|
||||
|
||||
@@ -20,10 +20,14 @@ OSDefineMetaClassAndStructors(SantaDecisionManager, OSObject);
|
||||
#pragma mark Object Lifecycle
|
||||
|
||||
bool SantaDecisionManager::init() {
|
||||
dataqueue_lock_ = IORWLockAlloc();
|
||||
cached_decisions_lock_ = IORWLockAlloc();
|
||||
sdm_lock_grp_ = lck_grp_alloc_init("santa-locks", lck_grp_attr_alloc_init());
|
||||
dataqueue_lock_ = lck_mtx_alloc_init(sdm_lock_grp_, lck_attr_alloc_init());
|
||||
cached_decisions_lock_ = lck_rw_alloc_init(sdm_lock_grp_, lck_attr_alloc_init());
|
||||
|
||||
cached_decisions_ = OSDictionary::withCapacity(1000);
|
||||
|
||||
owning_pid_ = 0;
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -34,15 +38,20 @@ void SantaDecisionManager::free() {
|
||||
}
|
||||
|
||||
if (cached_decisions_lock_) {
|
||||
IORWLockFree(cached_decisions_lock_);
|
||||
lck_rw_free(cached_decisions_lock_, sdm_lock_grp_);
|
||||
cached_decisions_lock_ = NULL;
|
||||
}
|
||||
|
||||
if (dataqueue_lock_ ) {
|
||||
IORWLockFree(dataqueue_lock_);
|
||||
lck_mtx_free(dataqueue_lock_, sdm_lock_grp_);
|
||||
dataqueue_lock_ = NULL;
|
||||
}
|
||||
|
||||
if (sdm_lock_grp_) {
|
||||
lck_grp_free(sdm_lock_grp_);
|
||||
sdm_lock_grp_ = NULL;
|
||||
}
|
||||
|
||||
super::free();
|
||||
}
|
||||
|
||||
@@ -54,16 +63,21 @@ void SantaDecisionManager::ConnectClient(IOSharedDataQueue *queue, pid_t pid) {
|
||||
|
||||
// Any decisions made while the daemon wasn't
|
||||
// connected should be cleared
|
||||
cached_decisions_->flushCollection();
|
||||
ClearCache();
|
||||
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
dataqueue_ = queue;
|
||||
dataqueue_->retain();
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
|
||||
owning_pid_ = pid;
|
||||
owning_proc_ = proc_find(pid);
|
||||
failed_queue_requests_ = 0;
|
||||
}
|
||||
|
||||
void SantaDecisionManager::DisconnectClient() {
|
||||
if (owning_pid_ < 1) return;
|
||||
|
||||
owning_pid_ = -1;
|
||||
|
||||
// Ask santad to shutdown, in case it's running.
|
||||
@@ -75,8 +89,10 @@ void SantaDecisionManager::DisconnectClient() {
|
||||
message.vnode_id = 0;
|
||||
PostToQueue(message);
|
||||
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
dataqueue_->release();
|
||||
dataqueue_ = NULL;
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
|
||||
proc_rele(owning_proc_);
|
||||
owning_proc_ = NULL;
|
||||
@@ -89,12 +105,6 @@ bool SantaDecisionManager::ClientConnected() {
|
||||
# pragma mark Listener Control
|
||||
|
||||
kern_return_t SantaDecisionManager::StartListener() {
|
||||
process_listener_ = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
|
||||
process_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
if (!process_listener_) return kIOReturnInternalError;
|
||||
LOGD("Process listener started.");
|
||||
|
||||
vnode_listener_ = kauth_listen_scope(KAUTH_SCOPE_VNODE,
|
||||
vnode_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
@@ -109,9 +119,6 @@ kern_return_t SantaDecisionManager::StopListener() {
|
||||
kauth_unlisten_scope(vnode_listener_);
|
||||
vnode_listener_ = NULL;
|
||||
|
||||
kauth_unlisten_scope(process_listener_);
|
||||
process_listener_ = NULL;
|
||||
|
||||
// Wait for any active invocations to finish before returning
|
||||
do {
|
||||
IOSleep(5);
|
||||
@@ -121,7 +128,6 @@ kern_return_t SantaDecisionManager::StopListener() {
|
||||
ClearCache();
|
||||
|
||||
LOGD("Vnode listener stopped.");
|
||||
LOGD("Process listener stopped.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
@@ -130,7 +136,7 @@ kern_return_t SantaDecisionManager::StopListener() {
|
||||
|
||||
void SantaDecisionManager::AddToCache(
|
||||
const char *identifier, santa_action_t decision, uint64_t microsecs) {
|
||||
IORWLockWrite(cached_decisions_lock_);
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
|
||||
if (cached_decisions_->getCount() > kMaxCacheSize) {
|
||||
// This could be made a _lot_ smarter, say only removing entries older
|
||||
@@ -155,17 +161,18 @@ void SantaDecisionManager::AddToCache(
|
||||
}
|
||||
}
|
||||
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
}
|
||||
|
||||
void SantaDecisionManager::CacheCheck(const char *identifier) {
|
||||
IORWLockRead(cached_decisions_lock_);
|
||||
lck_rw_lock_shared(cached_decisions_lock_);
|
||||
bool shouldInvalidate = (cached_decisions_->getObject(identifier) != NULL);
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
if (shouldInvalidate) {
|
||||
IORWLockWrite(cached_decisions_lock_);
|
||||
lck_rw_lock_shared_to_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->removeObject(identifier);
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
} else {
|
||||
lck_rw_unlock_shared(cached_decisions_lock_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,23 +181,23 @@ uint64_t SantaDecisionManager::CacheCount() {
|
||||
}
|
||||
|
||||
void SantaDecisionManager::ClearCache() {
|
||||
IORWLockWrite(cached_decisions_lock_);
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->flushCollection();
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
}
|
||||
|
||||
santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
santa_action_t result = ACTION_UNSET;
|
||||
uint64_t decision_time = 0;
|
||||
|
||||
IORWLockRead(cached_decisions_lock_);
|
||||
lck_rw_lock_shared(cached_decisions_lock_);
|
||||
SantaMessage *cached_decision = OSDynamicCast(
|
||||
SantaMessage, cached_decisions_->getObject(identifier));
|
||||
if (cached_decision) {
|
||||
result = cached_decision->getAction();
|
||||
decision_time = cached_decision->getMicrosecs();
|
||||
}
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
lck_rw_unlock_shared(cached_decisions_lock_);
|
||||
|
||||
if (CHECKBW_RESPONSE_VALID(result)) {
|
||||
uint64_t diff_time = GetCurrentUptime();
|
||||
@@ -210,9 +217,9 @@ santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
}
|
||||
|
||||
if (decision_time < diff_time) {
|
||||
IORWLockWrite(cached_decisions_lock_);
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->removeObject(identifier);
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
return ACTION_UNSET;
|
||||
}
|
||||
}
|
||||
@@ -223,12 +230,12 @@ santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
# pragma mark Queue Management
|
||||
|
||||
bool SantaDecisionManager::PostToQueue(santa_message_t message) {
|
||||
IORWLockWrite(dataqueue_lock_);
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
bool kr = false;
|
||||
if (dataqueue_) {
|
||||
kr = dataqueue_->enqueue(&message, sizeof(message));
|
||||
}
|
||||
IORWLockUnlock(dataqueue_lock_);
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
return kr;
|
||||
}
|
||||
|
||||
@@ -258,9 +265,8 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
path[0] = '\0';
|
||||
}
|
||||
|
||||
// If daemon isn't connected, allow and cache
|
||||
if (owning_pid_ < 1) {
|
||||
LOGI("Exeuction request without daemon running: %s", path);
|
||||
if (!ClientConnected()) {
|
||||
LOGI("Execution request without daemon running: %s", path);
|
||||
AddToCache(vnode_id_str,
|
||||
ACTION_RESPOND_CHECKBW_ALLOW,
|
||||
GetCurrentUptime());
|
||||
@@ -280,6 +286,11 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
do {
|
||||
// Send request to daemon...
|
||||
if (!PostToQueue(message)) {
|
||||
OSIncrementAtomic(&failed_queue_requests_);
|
||||
if (failed_queue_requests_ > kMaxQueueFailures) {
|
||||
LOGE("Failed to queue more than %d requests, killing daemon", kMaxQueueFailures);
|
||||
proc_signal(owning_pid_, SIGKILL);
|
||||
}
|
||||
LOGE("Failed to queue request for %s.", path);
|
||||
CacheCheck(vnode_id_str);
|
||||
return ACTION_ERROR;
|
||||
@@ -335,38 +346,9 @@ void SantaDecisionManager::DecrementListenerInvocations() {
|
||||
OSDecrementAtomic(&listener_invocations_);
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::MatchesOwningPID(const pid_t other_pid) {
|
||||
return (owning_pid_ == other_pid);
|
||||
}
|
||||
|
||||
#undef super
|
||||
|
||||
#pragma mark Kauth Callbacks
|
||||
|
||||
extern "C" int process_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
|
||||
if (idata == NULL) {
|
||||
LOGE("Process callback established without valid decision manager.");
|
||||
return KAUTH_RESULT_ALLOW;
|
||||
}
|
||||
SantaDecisionManager *sdm = OSDynamicCast(
|
||||
SantaDecisionManager, reinterpret_cast<OSObject *>(idata));
|
||||
|
||||
// NOTE: this prevents a debugger from attaching to an existing santad
|
||||
// process but doesn't prevent starting santad under a debugger. This check
|
||||
// is only here to try and prevent the user from deadlocking their machine
|
||||
// by attaching a debugger, so if they work around it and end up deadlocking,
|
||||
// that's their problem.
|
||||
if (action == KAUTH_PROCESS_CANTRACE &&
|
||||
sdm->MatchesOwningPID(proc_pid((proc_t)arg0))) {
|
||||
*(reinterpret_cast<int *>(arg1)) = EPERM;
|
||||
LOGD("Denied debugger access");
|
||||
return KAUTH_RESULT_DENY;
|
||||
}
|
||||
|
||||
return KAUTH_RESULT_ALLOW;
|
||||
}
|
||||
#pragma mark Kauth Callback
|
||||
|
||||
extern "C" int vnode_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
@@ -391,7 +373,7 @@ extern "C" int vnode_scope_callback(
|
||||
// Don't operate on ACCESS events, as they're advisory
|
||||
if (action & KAUTH_VNODE_ACCESS) return returnResult;
|
||||
|
||||
// Filter for only WRITE_DATA actions
|
||||
// Filter for only writes
|
||||
if (action & KAUTH_VNODE_WRITE_DATA ||
|
||||
action & KAUTH_VNODE_APPEND_DATA ||
|
||||
action & KAUTH_VNODE_DELETE) {
|
||||
@@ -431,17 +413,7 @@ extern "C" int vnode_scope_callback(
|
||||
default:
|
||||
// NOTE: Any unknown response or error condition causes us to fail open.
|
||||
// Whilst from a security perspective this is bad, it's important that
|
||||
// we don't break user's machines. Every fallen open response will come
|
||||
// through this code path and cause this log entry to be created, so we
|
||||
// can investigate each case and try to fix the root cause.
|
||||
char path[MAX_PATH_LEN];
|
||||
int name_len = MAX_PATH_LEN;
|
||||
if (vn_getpath(vnode, path, &name_len) != 0) {
|
||||
path[0] = '\0';
|
||||
}
|
||||
LOGW("Didn't receive a valid response for %s. Received: %d.",
|
||||
path,
|
||||
returnedAction);
|
||||
// we don't break user's machines.
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ const int kMaxRequestLoops = 50;
|
||||
///
|
||||
const int kMaxCacheSize = 10000;
|
||||
|
||||
///
|
||||
/// Maximum number of PostToQueue failures to allow.
|
||||
///
|
||||
const int kMaxQueueFailures = 10;
|
||||
|
||||
///
|
||||
/// SantaDecisionManager is responsible for intercepting Vnode execute actions
|
||||
/// and responding to the request appropriately.
|
||||
@@ -83,10 +88,10 @@ class SantaDecisionManager : public OSObject {
|
||||
/// Returns whether a client is currently connected or not.
|
||||
bool ClientConnected();
|
||||
|
||||
/// Starts both kauth listeners.
|
||||
/// Starts the kauth listener.
|
||||
kern_return_t StartListener();
|
||||
|
||||
/// Stops both kauth listeners. After stopping new callback requests,
|
||||
/// Stops the kauth listener. After stopping new callback requests,
|
||||
/// waits until all current invocations have finished before clearing the
|
||||
/// cache and returning.
|
||||
kern_return_t StopListener();
|
||||
@@ -128,22 +133,21 @@ class SantaDecisionManager : public OSObject {
|
||||
/// Returns the current system uptime in microseconds
|
||||
uint64_t GetCurrentUptime();
|
||||
|
||||
|
||||
/// Increments the count of active vnode callback's pending.
|
||||
void IncrementListenerInvocations();
|
||||
|
||||
/// Decrements the count of active vnode callback's pending.
|
||||
void DecrementListenerInvocations();
|
||||
|
||||
/// Returns true if other_pid is the same as the current client pid.
|
||||
bool MatchesOwningPID(const pid_t other_pid);
|
||||
|
||||
private:
|
||||
lck_grp_t *sdm_lock_grp_;
|
||||
lck_rw_t *cached_decisions_lock_;
|
||||
lck_mtx_t *dataqueue_lock_;
|
||||
|
||||
OSDictionary *cached_decisions_;
|
||||
IORWLock *cached_decisions_lock_;
|
||||
|
||||
IOSharedDataQueue *dataqueue_;
|
||||
IORWLock *dataqueue_lock_;
|
||||
SInt32 failed_queue_requests_;
|
||||
|
||||
SInt32 listener_invocations_;
|
||||
|
||||
@@ -151,7 +155,6 @@ class SantaDecisionManager : public OSObject {
|
||||
proc_t owning_proc_;
|
||||
|
||||
kauth_listener_t vnode_listener_;
|
||||
kauth_listener_t process_listener_;
|
||||
};
|
||||
|
||||
///
|
||||
@@ -168,18 +171,4 @@ extern "C" int vnode_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
|
||||
///
|
||||
/// The kauth callback function for the Process scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested (KAUTH_PROCESS_{CANTRACE,CANSIGNAL})
|
||||
/// @param target process
|
||||
/// @param Pointer to an errno-style error.
|
||||
/// @param unused
|
||||
/// @param unused
|
||||
///
|
||||
extern "C" int process_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTADECISIONMANAGER_H
|
||||
|
||||
@@ -43,6 +43,8 @@ bool SantaDriverClient::start(IOService *provider) {
|
||||
|
||||
fSDM = fProvider->GetDecisionManager();
|
||||
|
||||
if (!fSDM) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,11 +62,15 @@ bool SantaDriverClient::terminate(IOOptionBits options) {
|
||||
fSDM->DisconnectClient();
|
||||
LOGI("Client disconnected.");
|
||||
|
||||
fSharedMemory->release();
|
||||
fDataQueue->release();
|
||||
if (fSharedMemory) {
|
||||
fSharedMemory->release();
|
||||
fSharedMemory = NULL;
|
||||
}
|
||||
|
||||
fSharedMemory = NULL;
|
||||
fDataQueue = NULL;
|
||||
if (fDataQueue) {
|
||||
fDataQueue->release();
|
||||
fDataQueue = NULL;
|
||||
}
|
||||
|
||||
if (fProvider && fProvider->isOpen(this)) fProvider->close(this);
|
||||
|
||||
@@ -94,6 +100,9 @@ IOReturn SantaDriverClient::clientMemoryForType(UInt32 type,
|
||||
fSharedMemory->retain(); // client will decrement this ref
|
||||
*memory = fSharedMemory;
|
||||
|
||||
fSDM->ConnectClient(fDataQueue, proc_selfpid());
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -122,10 +131,6 @@ IOReturn SantaDriverClient::open() {
|
||||
return kIOReturnVMError;
|
||||
}
|
||||
|
||||
fSDM->ConnectClient(fDataQueue, proc_selfpid());
|
||||
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
// The maximum number of messages can be kept in the IODataQueue at any time.
|
||||
const int kMaxQueueEvents = 64;
|
||||
const int kMaxQueueEvents = 256;
|
||||
|
||||
///
|
||||
/// This class is instantiated by IOKit when a new client process attempts to
|
||||
@@ -43,12 +43,6 @@ const int kMaxQueueEvents = 64;
|
||||
class com_google_SantaDriverClient : public IOUserClient {
|
||||
OSDeclareDefaultStructors(com_google_SantaDriverClient);
|
||||
|
||||
private:
|
||||
IOSharedDataQueue *fDataQueue;
|
||||
IOMemoryDescriptor *fSharedMemory;
|
||||
com_google_SantaDriver *fProvider;
|
||||
SantaDecisionManager *fSDM;
|
||||
|
||||
public:
|
||||
/// Called as part of IOServiceOpen in clients
|
||||
bool initWithTask(task_t owningTask, void *securityID, UInt32 type);
|
||||
@@ -122,6 +116,12 @@ class com_google_SantaDriverClient : public IOUserClient {
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
private:
|
||||
IOSharedDataQueue *fDataQueue;
|
||||
IOMemoryDescriptor *fSharedMemory;
|
||||
com_google_SantaDriver *fProvider;
|
||||
SantaDecisionManager *fSDM;
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTADRIVERUSERCLIENT_H
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
class SantaMessage : public OSObject {
|
||||
OSDeclareDefaultStructors(SantaMessage)
|
||||
|
||||
private:
|
||||
santa_action_t action_;
|
||||
uint64_t microsecs_;
|
||||
|
||||
public:
|
||||
// Returns the time the action was last set.
|
||||
uint64_t getMicrosecs() const;
|
||||
@@ -39,6 +35,10 @@ class SantaMessage : public OSObject {
|
||||
|
||||
// Sets the acion and receive time.
|
||||
void setAction(const santa_action_t action, const uint64_t microsecs);
|
||||
|
||||
private:
|
||||
santa_action_t action_;
|
||||
uint64_t microsecs_;
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTAMESSAGE_H
|
||||
|
||||
@@ -55,18 +55,17 @@ static NSMutableDictionary *registeredCommands;
|
||||
+ (NSString *)helpForCommandWithName:(NSString *)commandName {
|
||||
Class<SNTCommand> command = registeredCommands[commandName];
|
||||
if (command) {
|
||||
NSMutableString *helpText = [[NSMutableString alloc] init];
|
||||
[helpText appendFormat:@"Help for '%@':\n", commandName];
|
||||
[helpText appendString:[command longHelpText]];
|
||||
return helpText;
|
||||
NSString *longHelp = [command longHelpText];
|
||||
if (longHelp) {
|
||||
return [NSString stringWithFormat:@"Help for '%@':\n%@", commandName, longHelp];
|
||||
} else {
|
||||
return @"This command does not have any help information.";
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (SNTXPCConnection *)connectToDaemon {
|
||||
// TODO(rah): Re-factor this so that successfully establishing the connection runs the command,
|
||||
// instead of having to sleep until the connection is made.
|
||||
|
||||
SNTXPCConnection *daemonConn =
|
||||
[[SNTXPCConnection alloc] initClientWithName:[SNTXPCControlInterface serviceId]
|
||||
options:NSXPCConnectionPrivileged];
|
||||
@@ -78,7 +77,7 @@ static NSMutableDictionary *registeredCommands;
|
||||
};
|
||||
|
||||
daemonConn.invalidationHandler = ^{
|
||||
printf("An error occurred communicating with the daemon\n");
|
||||
printf("An error occurred communicating with the daemon, is it running?\n");
|
||||
exit(1);
|
||||
};
|
||||
|
||||
|
||||
@@ -36,59 +36,61 @@ REGISTER_COMMAND_NAME(@"binaryinfo");
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Prints information about the given binary.";
|
||||
return @"Prints information about a binary.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return (@"The details provided will be the same ones Santa uses to make a decision about binaries"
|
||||
@"This includes SHA-1, SHA-256, code signing information and the type of binary");
|
||||
return (@"The details provided will be the same ones Santa uses to make a decision\n"
|
||||
@"about binaries. This includes SHA-256, SHA-1, code signing information and\n"
|
||||
@"the type of binary.");
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
NSString *filePath = [arguments firstObject];
|
||||
|
||||
if (!filePath) {
|
||||
LOGI(@"Missing file path");
|
||||
printf("Missing file path\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:filePath];
|
||||
if (!fileInfo) {
|
||||
LOGI(@"Invalid file");
|
||||
printf("Invalid file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LOGI(@"Info for file: %@", [fileInfo path]);
|
||||
LOGI(@"-----------------------------------------------------------");
|
||||
LOGI(@"%-20s: %@", "SHA-1", [fileInfo SHA1]);
|
||||
LOGI(@"%-20s: %@", "SHA-256", [fileInfo SHA256]);
|
||||
printf("%-12s: %s\n", "Path", [[fileInfo path] UTF8String]);
|
||||
printf("%-12s: %s\n", "SHA-256", [[fileInfo SHA256] UTF8String]);
|
||||
printf("%-12s: %s\n", "SHA-1", [[fileInfo SHA1] UTF8String]);
|
||||
|
||||
NSArray *archs = [fileInfo architectures];
|
||||
if (archs) {
|
||||
LOGI(@"%-20s: %@ (%@)", "Type", [fileInfo machoType], [archs componentsJoinedByString:@", "]);
|
||||
printf("%-12s: %s (%s)\n", "Type",
|
||||
[[fileInfo machoType] UTF8String],
|
||||
[[archs componentsJoinedByString:@", "] UTF8String]);
|
||||
} else {
|
||||
LOGI(@"%-20s: %@", "Type", [fileInfo machoType]);
|
||||
printf("%-12s: %s\n", "Type", [[fileInfo machoType] UTF8String]);
|
||||
}
|
||||
|
||||
SNTCodesignChecker *csc = [[SNTCodesignChecker alloc] initWithBinaryPath:filePath];
|
||||
|
||||
LOGI(@"%-20s: %s", "Code-signed", (csc) ? "Yes" : "No");
|
||||
printf("%-12s: %s\n", "Code-signed", (csc) ? "Yes" : "No");
|
||||
|
||||
if (csc) {
|
||||
LOGI(@"Signing chain\n");
|
||||
printf("Signing chain:\n");
|
||||
|
||||
[csc.certificates enumerateObjectsUsingBlock:^(SNTCertificate *c,
|
||||
unsigned long idx,
|
||||
BOOL *stop) {
|
||||
idx++; // index from 1
|
||||
LOGI(@" %2lu. %-20s: %@", idx, "SHA-1", c.SHA1);
|
||||
LOGI(@" %-20s: %@", "SHA-256", c.SHA256);
|
||||
LOGI(@" %-20s: %@", "Common Name", c.commonName);
|
||||
LOGI(@" %-20s: %@", "Organization", c.orgName);
|
||||
LOGI(@" %-20s: %@", "Organizational Unit", c.orgUnit);
|
||||
LOGI(@" %-20s: %@", "Valid From", c.validFrom);
|
||||
LOGI(@" %-20s: %@", "Valid Until", c.validUntil);
|
||||
LOGI(@"");
|
||||
printf(" %2lu. %-20s: %s\n", idx, "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("\n");
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ REGISTER_COMMAND_NAME(@"flushcache");
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Flush the kernel cache";
|
||||
return @"Flush the kernel cache.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return @"Flushes the in-kernel cache of whitelisted binaries.\n\n"
|
||||
@"Returns 0 if successful, 1 otherwise";
|
||||
return (@"Flushes the in-kernel cache of whitelisted binaries.\n"
|
||||
@"Returns 0 if successful, 1 otherwise");
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
|
||||
@@ -43,18 +43,17 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Adds a rule for the given binary or hash.";
|
||||
return @"Manually add/remove rules.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return (@"santactl rule {add|remove}\n"
|
||||
@"--whitelist: add to whitelist\n"
|
||||
@"--blacklist: add to blacklist\n"
|
||||
@"--silent-blacklist: add to silent blacklist\n"
|
||||
@"--message {message}: custom message\n"
|
||||
@"--path {path}: path of binary to add\n"
|
||||
@"--sha256 {sha256}: hash to add\n"
|
||||
);
|
||||
return (@"Usage: santactl rule {add|remove} [options]\n"
|
||||
@" --whitelist: add to whitelist\n"
|
||||
@" --blacklist: add to blacklist\n"
|
||||
@" --silent-blacklist: add to silent blacklist\n"
|
||||
@" --message {message}: custom message\n"
|
||||
@" --path {path}: path of binary to add\n"
|
||||
@" --sha256 {sha256}: hash to add\n");
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
@@ -62,12 +61,12 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
|
||||
// Ensure we have no privileges
|
||||
if (!DropRootPrivileges()) {
|
||||
LOGE(@"Failed to drop root privileges. Exiting.");
|
||||
printf("Failed to drop root privileges.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ([config syncBaseURL] != nil) {
|
||||
LOGE(@"SyncBaseURL is set, rules are managed centrally");
|
||||
printf("SyncBaseURL is set, rules are managed centrally.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
|
||||
// add or remove
|
||||
if (!action) {
|
||||
LOGI(@"Missing action");
|
||||
printf("Missing action - add or remove?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
} else if ([action compare:@"remove" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_REMOVE;
|
||||
} else {
|
||||
LOGI(@"Unknown action, expected add or remove");
|
||||
printf("Unknown action, expected add or remove.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -105,44 +104,44 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
state = RULESTATE_SILENT_BLACKLIST;
|
||||
} else if ([argument compare:@"--message" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
LOGI(@"No message specified");
|
||||
printf("No message specified.\n");
|
||||
}
|
||||
|
||||
customMsg = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--path" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
LOGI(@"No path specified");
|
||||
printf("No path specified.\n");
|
||||
}
|
||||
|
||||
filePath = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--sha256" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
LOGI(@"No SHA-256 specified");
|
||||
printf("No SHA-256 specified.\n");
|
||||
}
|
||||
|
||||
SHA256 = [arguments objectAtIndex:i];
|
||||
} else {
|
||||
LOGI(@"Unknown argument %@", argument);
|
||||
printf("Unknown argument %s.\n", [argument UTF8String]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == RULESTATE_UNKNOWN) {
|
||||
LOGI(@"No state specified");
|
||||
printf("No state specified.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (filePath) {
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:filePath];
|
||||
if (!fileInfo) {
|
||||
LOGI(@"Not a regular file or executable bundle");
|
||||
printf("Not a regular file or executable bundle.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SHA256 = [fileInfo SHA256];
|
||||
} else if (SHA256) {
|
||||
} else {
|
||||
LOGI(@"No SHA-256 or binary specified");
|
||||
printf("No SHA-256 or binary specified.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -152,13 +151,13 @@ REGISTER_COMMAND_NAME(@"rule");
|
||||
newRule.type = RULETYPE_BINARY;
|
||||
newRule.customMsg = customMsg;
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule withReply:^{
|
||||
if (state == RULESTATE_REMOVE) {
|
||||
LOGI(@"Removed rule for SHA-256: %@", [newRule shasum]);
|
||||
} else {
|
||||
LOGI(@"Added rule for SHA-256: %@", [newRule shasum]);
|
||||
}
|
||||
exit(0);
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule cleanSlate:NO reply:^{
|
||||
if (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);
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
|
||||
#import "SNTCommandController.h"
|
||||
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@@ -38,85 +33,56 @@ REGISTER_COMMAND_NAME(@"status");
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Get status about Santa";
|
||||
return @"Show Santa status information.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return @"Returns status information about Santa.";
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
|
||||
// Version information
|
||||
LOGI(@">>> Versions");
|
||||
LOGI(@"%-30s | %@", "santa-driver version", [self kextVersion]);
|
||||
LOGI(@"%-30s | %@", "santad version", [self daemonVersion]);
|
||||
LOGI(@"%-30s | %@",
|
||||
"santactl version",
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]);
|
||||
LOGI(@"%-30s | %@", "SantaGUI version", [self guiVersion]);
|
||||
LOGI(@"");
|
||||
// Daemon status
|
||||
__block NSString *clientMode;
|
||||
[[daemonConn remoteObjectProxy] clientMode:^(santa_clientmode_t cm) {
|
||||
switch (cm) {
|
||||
case CLIENTMODE_MONITOR:
|
||||
clientMode = @"Monitor"; break;
|
||||
case CLIENTMODE_LOCKDOWN:
|
||||
clientMode = @"Lockdown"; break;
|
||||
default:
|
||||
clientMode = [NSString stringWithFormat:@"Unknown (%d)", cm]; break;
|
||||
}
|
||||
}];
|
||||
do { usleep(5000); } while (!clientMode);
|
||||
printf(">>> Daemon Info\n");
|
||||
printf(" %-25s | %s\n", "Mode", [clientMode UTF8String]);
|
||||
|
||||
// Kext status
|
||||
if (daemonConn) {
|
||||
__block uint64_t cacheCount = -1;
|
||||
[[daemonConn remoteObjectProxy] cacheCount:^(uint64_t count) {
|
||||
cacheCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (cacheCount == -1);
|
||||
LOGI(@">>> Kernel Info");
|
||||
LOGI(@"%-30s | %d", "Kernel cache count", cacheCount);
|
||||
LOGI(@"");
|
||||
__block uint64_t cacheCount = -1;
|
||||
[[daemonConn remoteObjectProxy] cacheCount:^(uint64_t count) {
|
||||
cacheCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (cacheCount == -1);
|
||||
printf(">>> Kernel Info\n");
|
||||
printf(" %-25s | %lld\n", "Kernel cache count", cacheCount);
|
||||
|
||||
// Database counts
|
||||
__block uint64_t eventCount = 1, binaryRuleCount = -1, certRuleCount = -1;
|
||||
[[daemonConn remoteObjectProxy] databaseRuleCounts:^(uint64_t binary, uint64_t certificate) {
|
||||
binaryRuleCount = binary;
|
||||
certRuleCount = certificate;
|
||||
}];
|
||||
[[daemonConn remoteObjectProxy] databaseEventCount:^(uint64_t count) {
|
||||
eventCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (eventCount == -1 || binaryRuleCount == -1 || certRuleCount == -1);
|
||||
LOGI(@">>> Database Info");
|
||||
LOGI(@"%-30s | %d", "Binary Rules", binaryRuleCount);
|
||||
LOGI(@"%-30s | %d", "Certificate Rules", certRuleCount);
|
||||
LOGI(@"%-30s | %d", "Events Pending Upload", eventCount);
|
||||
LOGI(@"");
|
||||
} else {
|
||||
LOGI(@">>> santad is not running, cannot provide any more information.");
|
||||
}
|
||||
// Database counts
|
||||
__block uint64_t eventCount = 1, binaryRuleCount = -1, certRuleCount = -1;
|
||||
[[daemonConn remoteObjectProxy] databaseRuleCounts:^(uint64_t binary, uint64_t certificate) {
|
||||
binaryRuleCount = binary;
|
||||
certRuleCount = certificate;
|
||||
}];
|
||||
[[daemonConn remoteObjectProxy] databaseEventCount:^(uint64_t count) {
|
||||
eventCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (eventCount == -1 || binaryRuleCount == -1 || certRuleCount == -1);
|
||||
|
||||
printf(">>> Database Info\n");
|
||||
printf(" %-25s | %lld\n", "Binary Rules", binaryRuleCount);
|
||||
printf(" %-25s | %lld\n", "Certificate Rules", certRuleCount);
|
||||
printf(" %-25s | %lld\n", "Events Pending Upload", eventCount);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+ (NSString *)kextVersion {
|
||||
NSDictionary *loadedKexts = CFBridgingRelease(
|
||||
KextManagerCopyLoadedKextInfo((__bridge CFArrayRef)@[ @(USERCLIENT_ID) ],
|
||||
(__bridge CFArrayRef)@[ @"CFBundleVersion" ]));
|
||||
|
||||
if (loadedKexts[@(USERCLIENT_ID)] && loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"]) {
|
||||
return loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
SNTFileInfo *driverInfo =
|
||||
[[SNTFileInfo alloc] initWithPath:@"/Library/Extensions/santa-driver.kext"];
|
||||
if (driverInfo) {
|
||||
return [driverInfo.bundleVersion stringByAppendingString:@" (unloaded)"];
|
||||
}
|
||||
|
||||
return @"not found";
|
||||
}
|
||||
|
||||
+ (NSString *)daemonVersion {
|
||||
SNTFileInfo *daemonInfo = [[SNTFileInfo alloc] initWithPath:@"/usr/libexec/santad"];
|
||||
return daemonInfo.bundleVersion;
|
||||
}
|
||||
|
||||
+ (NSString *)guiVersion {
|
||||
SNTFileInfo *guiInfo =
|
||||
[[SNTFileInfo alloc] initWithPath:@"/Applications/Santa.app/Contents/MacOS/Santa"];
|
||||
return guiInfo.bundleVersion;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
21
Source/santactl/sync/NSData+Zlib.h
Normal file
21
Source/santactl/sync/NSData+Zlib.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/// 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.
|
||||
|
||||
/// Category on NSData providing the option of getting zlib or gzip compressed data.
|
||||
@interface NSData (Zlib)
|
||||
|
||||
- (NSData *)zlibCompressed;
|
||||
- (NSData *)gzipCompressed;
|
||||
|
||||
@end
|
||||
66
Source/santactl/sync/NSData+Zlib.m
Normal file
66
Source/santactl/sync/NSData+Zlib.m
Normal file
@@ -0,0 +1,66 @@
|
||||
/// 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 "NSData+Zlib.h"
|
||||
|
||||
#import <zlib.h>
|
||||
|
||||
@implementation NSData (Zlib)
|
||||
|
||||
- (NSData *)compressIncludingGzipHeader:(BOOL)includeHeader {
|
||||
if ([self length]) {
|
||||
z_stream stream;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
stream.avail_in = (uint)[self length];
|
||||
stream.next_in = (Bytef *)[self bytes];
|
||||
stream.total_out = 0;
|
||||
stream.avail_out = 0;
|
||||
|
||||
int chunkSize = 16384;
|
||||
|
||||
int windowSize = 15;
|
||||
if (includeHeader) {
|
||||
windowSize += 16;
|
||||
}
|
||||
|
||||
if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, windowSize, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
|
||||
NSMutableData *data = [NSMutableData dataWithLength:chunkSize];
|
||||
while (stream.avail_out == 0) {
|
||||
if (stream.total_out >= [data length]) {
|
||||
data.length += chunkSize;
|
||||
}
|
||||
stream.next_out = (uint8_t *)[data mutableBytes] + stream.total_out;
|
||||
stream.avail_out = (uInt)([data length] - stream.total_out);
|
||||
deflate(&stream, Z_FINISH);
|
||||
}
|
||||
deflateEnd(&stream);
|
||||
data.length = stream.total_out;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)zlibCompressed {
|
||||
return [self compressIncludingGzipHeader:NO];
|
||||
}
|
||||
|
||||
- (NSData *)gzipCompressed {
|
||||
return [self compressIncludingGzipHeader:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -29,6 +29,11 @@
|
||||
///
|
||||
@property(nonatomic) NSString *userAgent;
|
||||
|
||||
///
|
||||
/// If set to YES, this session refuses redirect requests. Defaults to NO.
|
||||
///
|
||||
@property(nonatomic) BOOL refusesRedirects;
|
||||
|
||||
///
|
||||
/// If set, the server that we connect to _must_ match this string. Redirects to other
|
||||
/// hosts will not be allowed.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#import "SNTAuthenticatingURLSession.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDERDecoder.h"
|
||||
#import "SNTLogging.h"
|
||||
|
||||
@@ -69,13 +68,13 @@
|
||||
}
|
||||
|
||||
if (![protectionSpace.protocol isEqual:NSURLProtectionSpaceHTTPS]) {
|
||||
LOGD(@"Protection Space: %@ is not a secure protocol", protectionSpace.protocol);
|
||||
LOGE(@"%@ is not a secure protocol", protectionSpace.protocol);
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protectionSpace.receivesCredentialSecurely) {
|
||||
LOGD(@"Protection Space: secure authentication or protocol cannot be established.");
|
||||
LOGE(@"Secure authentication or protocol cannot be established.");
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
return;
|
||||
}
|
||||
@@ -98,7 +97,7 @@
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
|
||||
return;
|
||||
} else {
|
||||
LOGE(@"Server asked for client authentication but no usable client certificate found.");
|
||||
LOGE(@"Unable to verify server identity.");
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
return;
|
||||
}
|
||||
@@ -107,6 +106,18 @@
|
||||
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||
newRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
||||
if (self.refusesRedirects) {
|
||||
completionHandler(NULL);
|
||||
} else {
|
||||
completionHandler(request);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Private Helpers for URLSession:didReceiveChallenge:completionHandler:
|
||||
|
||||
///
|
||||
@@ -131,7 +142,7 @@
|
||||
NSError *error;
|
||||
NSData *data = [NSData dataWithContentsOfFile:self.clientCertFile options:0 error:&error];
|
||||
if (error) {
|
||||
LOGE(@"Client Trust: Couldn't open client certificate %@: %@",
|
||||
LOGD(@"Client Trust: Couldn't open client certificate %@: %@",
|
||||
self.clientCertFile,
|
||||
[error localizedDescription]);
|
||||
return nil;
|
||||
@@ -147,11 +158,12 @@
|
||||
NSArray *identities = CFBridgingRelease(cfIdentities);
|
||||
|
||||
if (err != errSecSuccess) {
|
||||
LOGE(@"Client Trust: Couldn't load client certificate %@: %d", self.clientCertFile, err);
|
||||
LOGD(@"Client Trust: Couldn't load client certificate %@: %d", self.clientCertFile, err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
foundIdentity = (__bridge SecIdentityRef)identities[0][(__bridge id)kSecImportItemIdentity];
|
||||
CFRetain(foundIdentity);
|
||||
} else {
|
||||
CFArrayRef cfIdentities;
|
||||
err = SecItemCopyMatching((__bridge CFDictionaryRef)@{
|
||||
@@ -169,56 +181,65 @@
|
||||
|
||||
// Manually iterate through available identities to find one with an allowed issuer.
|
||||
[identities enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
SecIdentityRef identityRef = (__bridge SecIdentityRef)obj;
|
||||
SecIdentityRef identityRef = (__bridge SecIdentityRef)obj;
|
||||
|
||||
SecCertificateRef certificate = NULL;
|
||||
err = SecIdentityCopyCertificate(identityRef, &certificate);
|
||||
if (err != errSecSuccess) {
|
||||
LOGD(@"Client Trust: Failed to read certificate data: %d. Skipping identity.", (int)err);
|
||||
return;
|
||||
}
|
||||
|
||||
SNTCertificate *clientCert = [[SNTCertificate alloc] initWithSecCertificateRef:certificate];
|
||||
CFRelease(certificate);
|
||||
|
||||
// Switch identity finding method depending on config
|
||||
if (self.clientCertCommonName && clientCert.commonName) {
|
||||
if ([clientCert.commonName compare:self.clientCertCommonName
|
||||
options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
foundIdentity = identityRef;
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
SecCertificateRef certificate = NULL;
|
||||
err = SecIdentityCopyCertificate(identityRef, &certificate);
|
||||
if (err != errSecSuccess) {
|
||||
LOGD(@"Client Trust: Failed to read certificate data: %d. Skipping identity.", (int)err);
|
||||
return;
|
||||
}
|
||||
} else if (self.clientCertIssuerCn && clientCert.issuerCommonName) {
|
||||
if ([clientCert.issuerCommonName compare:self.clientCertIssuerCn
|
||||
options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
foundIdentity = identityRef;
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
} else {
|
||||
for (NSData *allowedIssuer in protectionSpace.distinguishedNames) {
|
||||
SNTDERDecoder *decoder = [[SNTDERDecoder alloc] initWithData:allowedIssuer];
|
||||
if (!decoder) continue;
|
||||
if ([clientCert.issuerCommonName isEqual:decoder.commonName] &&
|
||||
[clientCert.issuerCountryName isEqual:decoder.countryName] &&
|
||||
[clientCert.issuerOrgName isEqual:decoder.organizationName] &&
|
||||
[clientCert.issuerOrgUnit isEqual:decoder.organizationalUnit]) {
|
||||
|
||||
SNTCertificate *clientCert = [[SNTCertificate alloc] initWithSecCertificateRef:certificate];
|
||||
CFRelease(certificate);
|
||||
|
||||
// Switch identity finding method depending on config
|
||||
if (self.clientCertCommonName && clientCert.commonName) {
|
||||
if ([clientCert.commonName compare:self.clientCertCommonName
|
||||
options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
foundIdentity = identityRef;
|
||||
CFRetain(foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
} else if (self.clientCertIssuerCn && clientCert.issuerCommonName) {
|
||||
if ([clientCert.issuerCommonName compare:self.clientCertIssuerCn
|
||||
options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
foundIdentity = identityRef;
|
||||
CFRetain(foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
} else {
|
||||
for (NSData *allowedIssuer in protectionSpace.distinguishedNames) {
|
||||
SNTDERDecoder *decoder = [[SNTDERDecoder alloc] initWithData:allowedIssuer];
|
||||
if (!decoder) continue;
|
||||
if ([clientCert.issuerCommonName isEqual:decoder.commonName] &&
|
||||
[clientCert.issuerCountryName isEqual:decoder.countryName] &&
|
||||
[clientCert.issuerOrgName isEqual:decoder.organizationName] &&
|
||||
[clientCert.issuerOrgUnit isEqual:decoder.organizationalUnit]) {
|
||||
|
||||
foundIdentity = identityRef;
|
||||
CFRetain(foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
if (foundIdentity) {
|
||||
LOGD(@"Client Trust: Valid client identity %@.", foundIdentity);
|
||||
return [NSURLCredential credentialWithIdentity:foundIdentity
|
||||
certificates:nil
|
||||
persistence:NSURLCredentialPersistenceForSession];
|
||||
SecCertificateRef certificate = NULL;
|
||||
err = SecIdentityCopyCertificate(foundIdentity, &certificate);
|
||||
SNTCertificate *clientCert = [[SNTCertificate alloc] initWithSecCertificateRef:certificate];
|
||||
LOGD(@"Client Trust: Valid client identity %@.", clientCert);
|
||||
NSURLCredential *cred =
|
||||
[NSURLCredential credentialWithIdentity:foundIdentity
|
||||
certificates:nil
|
||||
persistence:NSURLCredentialPersistenceForSession];
|
||||
CFRelease(foundIdentity);
|
||||
return cred;
|
||||
} else {
|
||||
LOGD(@"Client Trust: No valid identity found.");
|
||||
return nil;
|
||||
@@ -260,7 +281,7 @@
|
||||
// Set this array of certs as the anchors to trust.
|
||||
err = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)certRefs);
|
||||
if (err != errSecSuccess) {
|
||||
LOGE(@"Server Trust: Could not set anchor certificates: %d", err);
|
||||
LOGD(@"Server Trust: Could not set anchor certificates: %d", err);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
@@ -269,7 +290,7 @@
|
||||
SecTrustResultType result = kSecTrustResultInvalid;
|
||||
err = SecTrustEvaluate(serverTrust, &result);
|
||||
if (err != errSecSuccess) {
|
||||
LOGE(@"Server Trust: Unable to evaluate certificate chain for server: %d", err);
|
||||
LOGD(@"Server Trust: Unable to evaluate certificate chain for server: %d", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -283,7 +304,7 @@
|
||||
// Having a trust level "unspecified" by the user is the usual result, described at
|
||||
// https://developer.apple.com/library/mac/qa/qa1360
|
||||
if (result != kSecTrustResultProceed && result != kSecTrustResultUnspecified) {
|
||||
LOGE(@"Server Trust: Server isn't trusted. SecTrustResultType: %d", result);
|
||||
LOGD(@"Server Trust: Server isn't trusted. SecTrustResultType: %d", result);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,18 +20,17 @@
|
||||
#import "SNTCommandSyncPostflight.h"
|
||||
#import "SNTCommandSyncPreflight.h"
|
||||
#import "SNTCommandSyncRuleDownload.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@interface SNTCommandSync : NSObject<SNTCommand>
|
||||
@property NSURLSession *session;
|
||||
@property SNTXPCConnection *daemonConn;
|
||||
@property SNTCommandSyncStatus *progress;
|
||||
@property SNTCommandSyncState *syncState;
|
||||
@end
|
||||
|
||||
@implementation SNTCommandSync
|
||||
@@ -47,11 +46,11 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Synchronizes Santa with the server";
|
||||
return @"Synchronizes Santa with the server.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return @"";
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
@@ -78,6 +77,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
if (santactlVersion) {
|
||||
authURLSession.userAgent = [authURLSession.userAgent stringByAppendingString:santactlVersion];
|
||||
}
|
||||
authURLSession.refusesRedirects = YES;
|
||||
|
||||
// Configure server auth
|
||||
if ([config syncServerAuthRootsFile]) {
|
||||
@@ -112,24 +112,28 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
s.daemonConn = daemonConn;
|
||||
|
||||
// Gather some data needed during some sync stages
|
||||
s.progress = [[SNTCommandSyncStatus alloc] init];
|
||||
s.syncState = [[SNTCommandSyncState alloc] init];
|
||||
|
||||
s.progress.syncBaseURL = config.syncBaseURL;
|
||||
if (!s.progress.syncBaseURL) {
|
||||
s.syncState.syncBaseURL = config.syncBaseURL;
|
||||
if (!s.syncState.syncBaseURL) {
|
||||
LOGE(@"Missing SyncBaseURL. Can't sync without it.");
|
||||
exit(1);
|
||||
} else if (![s.syncState.syncBaseURL.scheme isEqual:@"https"]) {
|
||||
LOGW(@"SyncBaseURL is not over HTTPS!");
|
||||
}
|
||||
authURLSession.serverHostname = s.progress.syncBaseURL.host;
|
||||
authURLSession.serverHostname = s.syncState.syncBaseURL.host;
|
||||
|
||||
s.progress.machineID = config.machineIDOverride;
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
s.progress.machineID = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
s.syncState.machineID = config.machineID;
|
||||
if ([s.syncState.machineID length] == 0) {
|
||||
LOGE(@"Missing Machine ID. Can't sync without it.");
|
||||
exit(1);
|
||||
}
|
||||
s.progress.machineOwner = config.machineOwner;
|
||||
|
||||
s.syncState.machineOwner = config.machineOwner;
|
||||
if ([s.syncState.machineOwner length] == 0) {
|
||||
s.syncState.machineOwner = @"";
|
||||
LOGW(@"Missing Machine Owner.");
|
||||
}
|
||||
|
||||
if (arguments.count == 2 && [[arguments firstObject] isEqual:@"singleevent"]) {
|
||||
[s eventUploadSingleEvent:arguments[1]];
|
||||
@@ -140,12 +144,12 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)preflight {
|
||||
[SNTCommandSyncPreflight performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Preflight complete");
|
||||
if (self.progress.uploadLogURL) {
|
||||
if (self.syncState.uploadLogURL) {
|
||||
[self logUpload];
|
||||
} else {
|
||||
[self eventUpload];
|
||||
@@ -159,7 +163,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)logUpload {
|
||||
[SNTCommandSyncLogUpload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
@@ -174,7 +178,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)eventUpload {
|
||||
[SNTCommandSyncEventUpload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
@@ -190,7 +194,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
- (void)eventUploadSingleEvent:(NSString *)sha256 {
|
||||
[SNTCommandSyncEventUpload uploadSingleEventWithSHA256:sha256
|
||||
session:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
@@ -205,7 +209,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)ruleDownload {
|
||||
[SNTCommandSyncRuleDownload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
@@ -220,7 +224,7 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)postflight {
|
||||
[SNTCommandSyncPostflight performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
|
||||
79
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
79
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/// 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.
|
||||
|
||||
extern NSString * const kURLPreflight;
|
||||
extern NSString * const kURLEventUpload;
|
||||
extern NSString * const kURLRuleDownload;
|
||||
extern NSString * const kURLPostflight;
|
||||
|
||||
extern NSString * const kSerialNumber;
|
||||
extern NSString * const kHostname;
|
||||
extern NSString * const kSantaVer;
|
||||
extern NSString * const kOSVer;
|
||||
extern NSString * const kOSBuild;
|
||||
extern NSString * const kPrimaryUser;
|
||||
extern NSString * const kRequestCleanSync;
|
||||
extern NSString * const kBatchSize;
|
||||
extern NSString * const kUploadLogsURL;
|
||||
extern NSString * const kClientMode;
|
||||
extern NSString * const kClientModeMonitor;
|
||||
extern NSString * const kClientModeLockdown;
|
||||
extern NSString * const kCleanSync;
|
||||
|
||||
extern NSString * const kEvents;
|
||||
extern NSString * const kFileSHA256;
|
||||
extern NSString * const kFilePath;
|
||||
extern NSString * const kFileName;
|
||||
extern NSString * const kExecutingUser;
|
||||
extern NSString * const kExecutionTime;
|
||||
extern NSString * const kDecision;
|
||||
extern NSString * const kDecisionAllowUnknown;
|
||||
extern NSString * const kDecisionAllowBinary;
|
||||
extern NSString * const kDecisionAllowCertificate;
|
||||
extern NSString * const kDecisionAllowScope;
|
||||
extern NSString * const kDecisionBlockUnknown;
|
||||
extern NSString * const kDecisionBlockBinary;
|
||||
extern NSString * const kDecisionBlockCertificate;
|
||||
extern NSString * const kDecisionBlockScope;
|
||||
extern NSString * const kDecisionUnknown;
|
||||
extern NSString * const kLoggedInUsers;
|
||||
extern NSString * const kCurrentSessions;
|
||||
extern NSString * const kFileBundleID;
|
||||
extern NSString * const kFileBundleName;
|
||||
extern NSString * const kFileBundleVersion;
|
||||
extern NSString * const kFileBundleShortVersionString;
|
||||
extern NSString * const kPID;
|
||||
extern NSString * const kPPID;
|
||||
extern NSString * const kSigningChain;
|
||||
extern NSString * const kCertSHA256;
|
||||
extern NSString * const kCertCN;
|
||||
extern NSString * const kCertOrg;
|
||||
extern NSString * const kCertOU;
|
||||
extern NSString * const kCertValidFrom;
|
||||
extern NSString * const kCertValidUntil;
|
||||
|
||||
extern NSString * const kLogUploadField;
|
||||
|
||||
extern NSString * const kRules;
|
||||
extern NSString * const kRuleSHA256;
|
||||
extern NSString * const kRulePolicy;
|
||||
extern NSString * const kRulePolicyWhitelist;
|
||||
extern NSString * const kRulePolicyBlacklist;
|
||||
extern NSString * const kRulePolicySilentBlacklist;
|
||||
extern NSString * const kRulePolicyRemove;
|
||||
extern NSString * const kRuleType;
|
||||
extern NSString * const kRuleTypeBinary;
|
||||
extern NSString * const kRuleTypeCertificate;
|
||||
extern NSString * const kRuleCustomMsg;
|
||||
extern NSString * const kCursor;
|
||||
81
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
81
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
@@ -0,0 +1,81 @@
|
||||
/// 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 "SNTCommandSyncConstants.h"
|
||||
|
||||
NSString * const kURLPreflight = @"preflight/";
|
||||
NSString * const kURLEventUpload = @"eventupload/";
|
||||
NSString * const kURLRuleDownload = @"ruledownload/";
|
||||
NSString * const kURLPostflight = @"postflight/";
|
||||
|
||||
NSString * const kSerialNumber = @"serial_num";
|
||||
NSString * const kHostname = @"hostname";
|
||||
NSString * const kSantaVer = @"santa_version";
|
||||
NSString * const kOSVer = @"os_version";
|
||||
NSString * const kOSBuild = @"os_build";
|
||||
NSString * const kPrimaryUser = @"primary_user";
|
||||
NSString * const kRequestCleanSync = @"request_clean_sync";
|
||||
NSString * const kBatchSize = @"batch_size";
|
||||
NSString * const kUploadLogsURL = @"upload_logs_url";
|
||||
NSString * const kClientMode = @"client_mode";
|
||||
NSString * const kClientModeMonitor = @"MONITOR";
|
||||
NSString * const kClientModeLockdown = @"LOCKDOWN";
|
||||
NSString * const kCleanSync = @"clean_sync";
|
||||
|
||||
NSString * const kEvents = @"events";
|
||||
NSString * const kFileSHA256 = @"file_sha256";
|
||||
NSString * const kFilePath = @"file_path";
|
||||
NSString * const kFileName = @"file_name";
|
||||
NSString * const kExecutingUser = @"executing_user";
|
||||
NSString * const kExecutionTime = @"execution_time";
|
||||
NSString * const kDecision = @"decision";
|
||||
NSString * const kDecisionAllowUnknown = @"ALLOW_UNKNOWN";
|
||||
NSString * const kDecisionAllowBinary = @"ALLOW_BINARY";
|
||||
NSString * const kDecisionAllowCertificate = @"ALLOW_CERTIFICATE";
|
||||
NSString * const kDecisionAllowScope = @"ALLOW_SCOPE";
|
||||
NSString * const kDecisionBlockUnknown = @"BLOCK_UNKNOWN";
|
||||
NSString * const kDecisionBlockBinary = @"BLOCK_BINARY";
|
||||
NSString * const kDecisionBlockCertificate = @"BLOCK_CERTIFICATE";
|
||||
NSString * const kDecisionBlockScope = @"BLOCK_SCOPE";
|
||||
NSString * const kDecisionUnknown = @"UNKNOWN";
|
||||
NSString * const kLoggedInUsers = @"logged_in_users";
|
||||
NSString * const kCurrentSessions = @"current_sessions";
|
||||
NSString * const kFileBundleID = @"file_bundle_id";
|
||||
NSString * const kFileBundleName = @"file_bundle_name";
|
||||
NSString * const kFileBundleVersion = @"file_bundle_version";
|
||||
NSString * const kFileBundleShortVersionString = @"file_bundle_version_string";
|
||||
NSString * const kPID = @"pid";
|
||||
NSString * const kPPID = @"ppid";
|
||||
NSString * const kSigningChain = @"signing_chain";
|
||||
NSString * const kCertSHA256 = @"sha256";
|
||||
NSString * const kCertCN = @"cn";
|
||||
NSString * const kCertOrg = @"org";
|
||||
NSString * const kCertOU = @"ou";
|
||||
NSString * const kCertValidFrom = @"valid_from";
|
||||
NSString * const kCertValidUntil = @"valid_until";
|
||||
|
||||
NSString * const kLogUploadField = @"files";
|
||||
|
||||
NSString * const kRules = @"rules";
|
||||
NSString * const kRuleSHA256 = @"sha256";
|
||||
NSString * const kRulePolicy = @"policy";
|
||||
NSString * const kRulePolicyWhitelist = @"WHITELIST";
|
||||
NSString * const kRulePolicyBlacklist = @"BLACKLIST";
|
||||
NSString * const kRulePolicySilentBlacklist = @"SILENT_BLACKLIST";
|
||||
NSString * const kRulePolicyRemove = @"REMOVE";
|
||||
NSString * const kRuleType = @"rule_type";
|
||||
NSString * const kRuleTypeBinary = @"BINARY";
|
||||
NSString * const kRuleTypeCertificate = @"CERTIFICATE";
|
||||
NSString * const kRuleCustomMsg = @"custom_msg";
|
||||
NSString * const kCursor = @"cursor";
|
||||
@@ -12,19 +12,19 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncEventUpload : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
@@ -25,11 +26,11 @@
|
||||
@implementation SNTCommandSyncEventUpload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"eventupload/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseEventsPending:^(NSArray *events) {
|
||||
if ([events count] == 0) {
|
||||
@@ -38,7 +39,7 @@
|
||||
[self uploadEventsFromArray:events
|
||||
toURL:url
|
||||
inSession:session
|
||||
batchSize:progress.eventBatchSize
|
||||
batchSize:syncState.eventBatchSize
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
}
|
||||
@@ -47,12 +48,12 @@
|
||||
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"eventupload/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA256:SHA256 withReply:^(SNTStoredEvent *event) {
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA256:SHA256 reply:^(SNTStoredEvent *event) {
|
||||
if (!event) {
|
||||
handler(YES);
|
||||
return;
|
||||
@@ -83,7 +84,7 @@
|
||||
if (eventIds.count >= batchSize) break;
|
||||
}
|
||||
|
||||
NSDictionary *uploadReq = @{ @"events": uploadEvents };
|
||||
NSDictionary *uploadReq = @{ kEvents: uploadEvents };
|
||||
|
||||
NSData *requestBody;
|
||||
@try {
|
||||
@@ -101,8 +102,11 @@
|
||||
[[session dataTaskWithRequest:req completionHandler:^(NSData *data,
|
||||
NSURLResponse *response,
|
||||
NSError *error) {
|
||||
if ([(NSHTTPURLResponse *)response statusCode] != 200) {
|
||||
LOGD(@"HTTP Response Code: %d", [(NSHTTPURLResponse *)response statusCode]);
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGE(@"HTTP Response: %d %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
LOGI(@"Uploaded %d events", eventIds.count);
|
||||
@@ -129,35 +133,53 @@
|
||||
#define ADDKEY(dict, key, value) if (value) dict[key] = value
|
||||
NSMutableDictionary *newEvent = [NSMutableDictionary dictionary];
|
||||
|
||||
ADDKEY(newEvent, @"file_sha256", event.fileSHA256);
|
||||
ADDKEY(newEvent, @"file_path", [event.filePath stringByDeletingLastPathComponent]);
|
||||
ADDKEY(newEvent, @"file_name", [event.filePath lastPathComponent]);
|
||||
ADDKEY(newEvent, @"executing_user", event.executingUser);
|
||||
ADDKEY(newEvent, @"execution_time", @([event.occurrenceDate timeIntervalSince1970]));
|
||||
ADDKEY(newEvent, @"decision", @(event.decision));
|
||||
ADDKEY(newEvent, @"logged_in_users", event.loggedInUsers);
|
||||
ADDKEY(newEvent, @"current_sessions", event.currentSessions);
|
||||
ADDKEY(newEvent, kFileSHA256, event.fileSHA256);
|
||||
ADDKEY(newEvent, kFilePath, [event.filePath stringByDeletingLastPathComponent]);
|
||||
ADDKEY(newEvent, kFileName, [event.filePath lastPathComponent]);
|
||||
ADDKEY(newEvent, kExecutingUser, event.executingUser);
|
||||
ADDKEY(newEvent, kExecutionTime, @([event.occurrenceDate timeIntervalSince1970]));
|
||||
ADDKEY(newEvent, kLoggedInUsers, event.loggedInUsers);
|
||||
ADDKEY(newEvent, kCurrentSessions, event.currentSessions);
|
||||
|
||||
ADDKEY(newEvent, @"file_bundle_id", event.fileBundleID);
|
||||
ADDKEY(newEvent, @"file_bundle_name", event.fileBundleName);
|
||||
ADDKEY(newEvent, @"file_bundle_version", event.fileBundleVersion);
|
||||
ADDKEY(newEvent, @"file_bundle_version_string", event.fileBundleVersionString);
|
||||
switch (event.decision) {
|
||||
case EVENTSTATE_ALLOW_UNKNOWN: ADDKEY(newEvent, kDecision, kDecisionAllowUnknown); break;
|
||||
case EVENTSTATE_ALLOW_BINARY: ADDKEY(newEvent, kDecision, kDecisionAllowBinary); break;
|
||||
case EVENTSTATE_ALLOW_CERTIFICATE:
|
||||
ADDKEY(newEvent, kDecision, kDecisionAllowCertificate);
|
||||
break;
|
||||
case EVENTSTATE_ALLOW_SCOPE: ADDKEY(newEvent, kDecision, kDecisionAllowScope); break;
|
||||
case EVENTSTATE_BLOCK_UNKNOWN: ADDKEY(newEvent, kDecision, kDecisionBlockUnknown); break;
|
||||
case EVENTSTATE_BLOCK_BINARY: ADDKEY(newEvent, kDecision, kDecisionBlockBinary); break;
|
||||
case EVENTSTATE_BLOCK_CERTIFICATE:
|
||||
ADDKEY(newEvent, kDecision, kDecisionBlockCertificate);
|
||||
break;
|
||||
case EVENTSTATE_BLOCK_SCOPE: ADDKEY(newEvent, kDecision, kDecisionBlockScope); break;
|
||||
default: ADDKEY(newEvent, kDecision, kDecisionUnknown);
|
||||
}
|
||||
|
||||
ADDKEY(newEvent, kFileBundleID, event.fileBundleID);
|
||||
ADDKEY(newEvent, kFileBundleName, event.fileBundleName);
|
||||
ADDKEY(newEvent, kFileBundleVersion, event.fileBundleVersion);
|
||||
ADDKEY(newEvent, kFileBundleShortVersionString, event.fileBundleVersionString);
|
||||
|
||||
ADDKEY(newEvent, kPID, event.pid);
|
||||
ADDKEY(newEvent, kPPID, event.ppid);
|
||||
|
||||
NSMutableArray *signingChain = [NSMutableArray arrayWithCapacity:event.signingChain.count];
|
||||
for (int i = 0; i < event.signingChain.count; i++) {
|
||||
SNTCertificate *cert = [event.signingChain objectAtIndex:i];
|
||||
|
||||
NSMutableDictionary *certDict = [NSMutableDictionary dictionary];
|
||||
ADDKEY(certDict, @"sha256", cert.SHA256);
|
||||
ADDKEY(certDict, @"cn", cert.commonName);
|
||||
ADDKEY(certDict, @"org", cert.orgName);
|
||||
ADDKEY(certDict, @"ou", cert.orgUnit);
|
||||
ADDKEY(certDict, @"valid_from", @([cert.validFrom timeIntervalSince1970]));
|
||||
ADDKEY(certDict, @"valid_until", @([cert.validUntil timeIntervalSince1970]));
|
||||
ADDKEY(certDict, kCertSHA256, cert.SHA256);
|
||||
ADDKEY(certDict, kCertCN, cert.commonName);
|
||||
ADDKEY(certDict, kCertOrg, cert.orgName);
|
||||
ADDKEY(certDict, kCertOU, cert.orgUnit);
|
||||
ADDKEY(certDict, kCertValidFrom, @([cert.validFrom timeIntervalSince1970]));
|
||||
ADDKEY(certDict, kCertValidUntil, @([cert.validUntil timeIntervalSince1970]));
|
||||
|
||||
[signingChain addObject:certDict];
|
||||
}
|
||||
newEvent[@"signing_chain"] = signingChain;
|
||||
newEvent[kSigningChain] = signingChain;
|
||||
|
||||
return newEvent;
|
||||
#undef ADDKEY
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncLogUpload : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -14,27 +14,67 @@
|
||||
|
||||
#import "SNTCommandSyncLogUpload.h"
|
||||
|
||||
#import "NSData+Zlib.h"
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
|
||||
@implementation SNTCommandSyncLogUpload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = progress.uploadLogURL;
|
||||
NSURL *url = syncState.uploadLogURL;
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
NSString *boundary = @"santa-sync-upload-boundary";
|
||||
NSString *boundary = @"----santa-sync-upload-boundary";
|
||||
|
||||
NSString *contentType =
|
||||
[NSString stringWithFormat:@"multipart/form-data; charset=UTF-8; boundary=%@", boundary];
|
||||
[req setValue:contentType forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
// Prepare the body of the request, encoded as a multipart/form-data.
|
||||
// Along the way, gzip the individual log files and append .gz to their filenames.
|
||||
NSMutableData *reqBody = [[NSMutableData alloc] init];
|
||||
NSArray *logsToUpload = [SNTCommandSyncLogUpload logsToUpload];
|
||||
for (NSString *log in logsToUpload) {
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"Content-Disposition: form-data; "
|
||||
@"name=\"%@\"; "
|
||||
@"filename=\"%@.gz\"\r\n", kLogUploadField, [log lastPathComponent]]
|
||||
dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:
|
||||
[@"Content-Type: application/x-gzip\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:[[NSData dataWithContentsOfFile:log] gzipCompressed]];
|
||||
[reqBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
// Upload the logs
|
||||
[[session uploadTaskWithRequest:req
|
||||
fromData:reqBody
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGE(@"HTTP Response: %d %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
LOGI(@"Uploaded %d logs", [logsToUpload count]);
|
||||
handler(YES);
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
+ (NSArray *)logsToUpload {
|
||||
// General logs
|
||||
NSMutableArray *logsToUpload = [@[ @"/var/log/santa.log",
|
||||
@"/var/log/system.log" ] mutableCopy];
|
||||
@@ -51,38 +91,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the body of the request, encoded as a multipart/form-data.
|
||||
// Along the way, gzip the individual log files (they'll be stored in blobstore gzipped, which is
|
||||
// what we want) and append .gz to their filenames.
|
||||
NSMutableData *reqBody = [[NSMutableData alloc] init];
|
||||
for (NSString *log in logsToUpload) {
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"Content-Disposition: multipart/form-data; "
|
||||
@"name=\"files\"; "
|
||||
@"filename=\"%@.gz\"\r\n", [log lastPathComponent]]
|
||||
dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:
|
||||
[@"Content-Type: application/x-gzip\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[reqBody appendData:[NSData dataWithContentsOfFile:log]];
|
||||
[reqBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
[reqBody appendData:
|
||||
[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
// Upload the logs
|
||||
[[session uploadTaskWithRequest:req
|
||||
fromData:reqBody
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
if ([(NSHTTPURLResponse *)response statusCode] != 200) {
|
||||
LOGD(@"HTTP Response Code: %d", [(NSHTTPURLResponse *)response statusCode]);
|
||||
handler(NO);
|
||||
} else {
|
||||
LOGI(@"Uploaded %d logs", [logsToUpload count]);
|
||||
handler(YES);
|
||||
}
|
||||
}] resume];
|
||||
return logsToUpload;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncPostflight : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -16,28 +16,32 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
|
||||
@implementation SNTCommandSyncPostflight
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"postflight/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLPostflight stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
|
||||
[[session dataTaskWithRequest:req completionHandler:^(NSData *data,
|
||||
NSURLResponse *response,
|
||||
NSError *error) {
|
||||
if ([(NSHTTPURLResponse *)response statusCode] != 200) {
|
||||
LOGD(@"HTTP Response Code: %d", [(NSHTTPURLResponse *)response statusCode]);
|
||||
handler(NO);
|
||||
} else {
|
||||
handler(YES);
|
||||
}
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGE(@"HTTP Response: %d %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
handler(YES);
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncPreflight : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#include "SNTKernelCommon.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
@@ -25,20 +26,23 @@
|
||||
@implementation SNTCommandSyncPreflight
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"preflight/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLPreflight stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
|
||||
NSMutableDictionary *requestDict = [NSMutableDictionary dictionary];
|
||||
requestDict[@"serial_no"] = [SNTSystemInfo serialNumber];
|
||||
requestDict[@"hostname"] = [SNTSystemInfo shortHostname];
|
||||
requestDict[@"santa_version"] =
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
requestDict[@"os_version"] = [SNTSystemInfo osVersion];
|
||||
requestDict[@"os_build"] = [SNTSystemInfo osBuild];
|
||||
requestDict[@"primary_user"] = progress.machineOwner;
|
||||
requestDict[kSerialNumber] = [SNTSystemInfo serialNumber];
|
||||
requestDict[kHostname] = [SNTSystemInfo shortHostname];
|
||||
requestDict[kSantaVer] = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
requestDict[kOSVer] = [SNTSystemInfo osVersion];
|
||||
requestDict[kOSBuild] = [SNTSystemInfo osBuild];
|
||||
requestDict[kPrimaryUser] = syncState.machineOwner;
|
||||
|
||||
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--clean"]) {
|
||||
requestDict[kRequestCleanSync] = @YES;
|
||||
}
|
||||
|
||||
NSData *requestBody = [NSJSONSerialization dataWithJSONObject:requestDict
|
||||
options:0
|
||||
@@ -53,17 +57,25 @@
|
||||
NSError *error) {
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGD(@"HTTP Response: %@",
|
||||
LOGE(@"HTTP Response: %d %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
NSDictionary *r = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
|
||||
progress.eventBatchSize = [r[@"batch_size"] intValue];
|
||||
progress.uploadLogURL = [NSURL URLWithString:r[@"upload_logs_url"]];
|
||||
syncState.eventBatchSize = [r[kBatchSize] intValue];
|
||||
syncState.uploadLogURL = [NSURL URLWithString:r[kUploadLogsURL]];
|
||||
|
||||
if (r[@"client_mode"]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:[r[@"client_mode"] intValue] withReply:^{}];
|
||||
if ([r[kClientMode] isEqual:kClientModeMonitor]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_MONITOR reply:^{}];
|
||||
} else if ([r[kClientMode] isEqual:kClientModeLockdown]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_LOCKDOWN reply:^{}];
|
||||
}
|
||||
|
||||
if ([r[kCleanSync] boolValue]) {
|
||||
syncState.cleanSync = YES;
|
||||
LOGD(@"Clean sync requested by server");
|
||||
}
|
||||
|
||||
handler(YES);
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncRuleDownload : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
#import "SNTCommandSyncRuleDownload.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTRule.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
@@ -24,15 +25,15 @@
|
||||
@implementation SNTCommandSyncRuleDownload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"ruledownload/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLRuleDownload stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
[self ruleDownloadWithCursor:nil
|
||||
url:url
|
||||
session:session
|
||||
progress:progress
|
||||
syncState:syncState
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
}
|
||||
@@ -40,14 +41,14 @@
|
||||
+ (void)ruleDownloadWithCursor:(NSString *)cursor
|
||||
url:(NSURL *)url
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
|
||||
NSDictionary *requestDict = (cursor ? @{ @"cursor": cursor } : @{});
|
||||
NSDictionary *requestDict = (cursor ? @{ kCursor: cursor } : @{});
|
||||
|
||||
if (!progress.downloadedRules) {
|
||||
progress.downloadedRules = [NSMutableArray array];
|
||||
if (!syncState.downloadedRules) {
|
||||
syncState.downloadedRules = [NSMutableArray array];
|
||||
}
|
||||
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
@@ -69,38 +70,55 @@
|
||||
handler(NO);
|
||||
}
|
||||
|
||||
NSArray *receivedRules = resp[@"rules"];
|
||||
|
||||
NSArray *receivedRules = resp[kRules];
|
||||
for (NSDictionary *rule in receivedRules) {
|
||||
if (![rule isKindOfClass:[NSDictionary class]]) continue;
|
||||
|
||||
SNTRule *newRule = [[SNTRule alloc] init];
|
||||
newRule.shasum = rule[@"shasum"];
|
||||
newRule.shasum = rule[kRuleSHA256];
|
||||
|
||||
newRule.state = [rule[@"state"] intValue];
|
||||
if (newRule.state <= RULESTATE_UNKNOWN || newRule.state >= RULESTATE_MAX) continue;
|
||||
if ([rule[kRulePolicy] isEqual:kRulePolicyWhitelist]) {
|
||||
newRule.state = RULESTATE_WHITELIST;
|
||||
} else if ([rule[kRulePolicy] isEqual:kRulePolicyBlacklist]) {
|
||||
newRule.state = RULESTATE_BLACKLIST;
|
||||
} else if ([rule[kRulePolicy] isEqual:kRulePolicySilentBlacklist]) {
|
||||
newRule.state = RULESTATE_SILENT_BLACKLIST;
|
||||
} else if ([rule[kRulePolicy] isEqual:kRulePolicyRemove]) {
|
||||
newRule.state = RULESTATE_REMOVE;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
newRule.type = [rule[@"type"] intValue];
|
||||
if (newRule.type <= RULETYPE_UNKNOWN || newRule.type >= RULETYPE_MAX) continue;
|
||||
if ([rule[kRuleType] isEqual:kRuleTypeBinary]) {
|
||||
newRule.type = RULETYPE_BINARY;
|
||||
} else if ([rule[kRuleType] isEqual:kRuleTypeCertificate]) {
|
||||
newRule.type = RULETYPE_CERT;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString *customMsg = rule[@"custom_msg"];
|
||||
NSString *customMsg = rule[kRuleCustomMsg];
|
||||
if (customMsg) {
|
||||
newRule.customMsg = customMsg;
|
||||
}
|
||||
|
||||
[progress.downloadedRules addObject:newRule];
|
||||
[syncState.downloadedRules addObject:newRule];
|
||||
}
|
||||
|
||||
if (resp[@"cursor"]) {
|
||||
[self ruleDownloadWithCursor:resp[@"cursor"]
|
||||
if (resp[kCursor]) {
|
||||
[self ruleDownloadWithCursor:resp[kCursor]
|
||||
url:url
|
||||
session:session
|
||||
progress:progress
|
||||
syncState:syncState
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
} else {
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRules:progress.downloadedRules withReply:^{
|
||||
LOGI(@"Added %d rule(s)", progress.downloadedRules.count);
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRules:syncState.downloadedRules
|
||||
cleanSlate:syncState.cleanSync
|
||||
reply:^{
|
||||
if (syncState.downloadedRules.count) {
|
||||
LOGI(@"Added %d rule(s)", syncState.downloadedRules.count);
|
||||
}
|
||||
handler(YES);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/// 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 SNTCommandSyncStatus : NSObject
|
||||
@interface SNTCommandSyncState : NSObject
|
||||
|
||||
/// The base API URL
|
||||
@property NSURL *syncBaseURL;
|
||||
@@ -23,6 +23,10 @@
|
||||
@property NSString *machineID;
|
||||
@property NSString *machineOwner;
|
||||
|
||||
/// Clean sync flag, sent from server. If True, all existing rules
|
||||
/// should be deleted before inserting any new rules.
|
||||
@property BOOL cleanSync;
|
||||
|
||||
/// Batch size for uploading events, sent from server
|
||||
@property int32_t eventBatchSize;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
|
||||
@implementation SNTCommandSyncStatus
|
||||
@implementation SNTCommandSyncState
|
||||
@end
|
||||
@@ -1,3 +1,17 @@
|
||||
/// 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.
|
||||
|
||||
///
|
||||
/// This is a simple ASN.1 decoder that utilizes Apple's SecAsn1Decode
|
||||
/// to parse the @c distinguishedNames property of NSURLProtectionSpace.
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/// 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 "SNTDERDecoder.h"
|
||||
|
||||
#import <Security/SecAsn1Coder.h>
|
||||
|
||||
88
Source/santactl/version/SNTCommandVersion.m
Normal file
88
Source/santactl/version/SNTCommandVersion.m
Normal file
@@ -0,0 +1,88 @@
|
||||
/// 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 "SNTCommandController.h"
|
||||
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
|
||||
@interface SNTCommandVersion : NSObject<SNTCommand>
|
||||
@end
|
||||
|
||||
@implementation SNTCommandVersion
|
||||
|
||||
REGISTER_COMMAND_NAME(@"version");
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Show Santa component versions.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (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]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+ (NSString *)santaKextVersion {
|
||||
NSDictionary *loadedKexts = CFBridgingRelease(
|
||||
KextManagerCopyLoadedKextInfo((__bridge CFArrayRef)@[ @(USERCLIENT_ID) ],
|
||||
(__bridge CFArrayRef)@[ @"CFBundleVersion" ])
|
||||
);
|
||||
|
||||
if (loadedKexts[@(USERCLIENT_ID)] && loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"]) {
|
||||
return loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
SNTFileInfo *driverInfo =
|
||||
[[SNTFileInfo alloc] initWithPath:@"/Library/Extensions/santa-driver.kext"];
|
||||
if (driverInfo) {
|
||||
return [driverInfo.bundleVersion stringByAppendingString:@" (unloaded)"];
|
||||
}
|
||||
|
||||
return @"not found";
|
||||
}
|
||||
|
||||
+ (NSString *)santadVersion {
|
||||
SNTFileInfo *daemonInfo = [[SNTFileInfo alloc] initWithPath:@"/usr/libexec/santad"];
|
||||
return daemonInfo.bundleVersion;
|
||||
}
|
||||
|
||||
+ (NSString *)santaAppVersion {
|
||||
SNTFileInfo *guiInfo =
|
||||
[[SNTFileInfo alloc] initWithPath:@"/Applications/Santa.app/Contents/MacOS/Santa"];
|
||||
return guiInfo.bundleVersion;
|
||||
}
|
||||
|
||||
+ (NSString *)santactlVersion {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -13,6 +13,7 @@
|
||||
/// limitations under the License.
|
||||
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#import "SNTApplication.h"
|
||||
@@ -26,6 +27,7 @@
|
||||
#import "SNTDriverManager.h"
|
||||
#import "SNTEventTable.h"
|
||||
#import "SNTExecutionController.h"
|
||||
#import "SNTFileWatcher.h"
|
||||
#import "SNTRuleTable.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
@@ -35,6 +37,7 @@
|
||||
@property SNTDriverManager *driverManager;
|
||||
@property SNTEventTable *eventTable;
|
||||
@property SNTExecutionController *execController;
|
||||
@property SNTFileWatcher *configFileWatcher;
|
||||
@property SNTRuleTable *ruleTable;
|
||||
@property SNTXPCConnection *controlConnection;
|
||||
@property SNTXPCConnection *notifierConnection;
|
||||
@@ -82,19 +85,19 @@
|
||||
[[SNTDaemonControlController alloc] initWithDriverManager:_driverManager];
|
||||
[_controlConnection resume];
|
||||
|
||||
// Get client mode and begin observing for updates
|
||||
SNTConfigurator *configurator = [SNTConfigurator configurator];
|
||||
santa_clientmode_t clientMode = [configurator clientMode];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:@"clientMode"
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:NULL];
|
||||
_configFileWatcher = [[SNTFileWatcher alloc] initWithFilePath:kDefaultConfigFilePath
|
||||
handler:^{
|
||||
[[SNTConfigurator configurator] reloadConfigData];
|
||||
|
||||
// Ensure config file remains root:wheel 0644
|
||||
chown([kDefaultConfigFilePath fileSystemRepresentation], 0, 0);
|
||||
chmod([kDefaultConfigFilePath fileSystemRepresentation], 0644);
|
||||
}];
|
||||
|
||||
// Initialize the binary checker object
|
||||
_execController = [[SNTExecutionController alloc] initWithDriverManager:_driverManager
|
||||
ruleTable:_ruleTable
|
||||
eventTable:_eventTable
|
||||
operatingMode:clientMode
|
||||
notifierConnection:_notifierConnection];
|
||||
if (!_execController) return nil;
|
||||
}
|
||||
@@ -102,20 +105,13 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context {
|
||||
if ([keyPath isEqual:@"clientMode"]) {
|
||||
self.execController.operatingMode = [change[NSKeyValueChangeNewKey] intValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)run {
|
||||
LOGI(@"Connected to driver, activating.");
|
||||
|
||||
// Create a concurrent queue to put requests on, then set its priority to high.
|
||||
dispatch_queue_t q = dispatch_queue_create("com.google.santad.driver_queue",
|
||||
DISPATCH_QUEUE_CONCURRENT);
|
||||
dispatch_set_target_queue(q, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
|
||||
[self.driverManager listenWithBlock:^(santa_message_t message) {
|
||||
@autoreleasepool {
|
||||
@@ -138,6 +134,7 @@
|
||||
[self.execController validateBinaryWithPath:@(message.path)
|
||||
userName:userName
|
||||
pid:@(message.pid)
|
||||
ppid:@(message.ppid)
|
||||
vnodeId:message.vnode_id];
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -50,16 +50,16 @@
|
||||
reply([rdb binaryRuleCount], [rdb certificateRuleCount]);
|
||||
}
|
||||
|
||||
- (void)databaseRuleAddRule:(SNTRule *)rule withReply:(void (^)())reply {
|
||||
[self databaseRuleAddRules:@[ rule ] withReply:reply];
|
||||
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply {
|
||||
[self databaseRuleAddRules:@[ rule ] cleanSlate:cleanSlate reply:reply];
|
||||
}
|
||||
|
||||
- (void)databaseRuleAddRules:(NSArray *)rules withReply:(void (^)())reply {
|
||||
[[SNTDatabaseController ruleTable] addRules:rules];
|
||||
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply {
|
||||
[[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];
|
||||
if ([rules filteredArrayUsingPredicate:p].count) {
|
||||
if ([rules filteredArrayUsingPredicate:p].count || cleanSlate) {
|
||||
LOGI(@"Received non-whitelist rule, flushing cache");
|
||||
[self.driverManager flushCache];
|
||||
}
|
||||
@@ -71,7 +71,7 @@
|
||||
reply([[SNTDatabaseController eventTable] pendingEventsCount]);
|
||||
}
|
||||
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 withReply:(void (^)(SNTStoredEvent *))reply {
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 reply:(void (^)(SNTStoredEvent *))reply {
|
||||
reply([[SNTDatabaseController eventTable] pendingEventForSHA256:sha256]);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
reply([[SNTConfigurator configurator] clientMode]);
|
||||
}
|
||||
|
||||
- (void)setClientMode:(santa_clientmode_t)mode withReply:(void (^)())reply {
|
||||
- (void)setClientMode:(santa_clientmode_t)mode reply:(void (^)())reply {
|
||||
[[SNTConfigurator configurator] setClientMode:mode];
|
||||
reply();
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ static NSString * const kEventsDatabaseName = @"events.db";
|
||||
static FMDatabaseQueue *eventDatabaseQueue = nil;
|
||||
static dispatch_once_t eventDatabaseToken;
|
||||
dispatch_once(&eventDatabaseToken, ^{
|
||||
[self createDatabasePath];
|
||||
NSString *fullPath = [kDatabasePath stringByAppendingPathComponent:kEventsDatabaseName];
|
||||
eventDatabaseQueue = [[FMDatabaseQueue alloc] initWithPath:fullPath];
|
||||
[self createDatabasePath];
|
||||
NSString *fullPath = [kDatabasePath stringByAppendingPathComponent:kEventsDatabaseName];
|
||||
eventDatabaseQueue = [[FMDatabaseQueue alloc] initWithPath:fullPath];
|
||||
|
||||
#ifndef DEBUG
|
||||
[eventDatabaseQueue inDatabase:^(FMDatabase *db) {
|
||||
db.logsErrors = NO;
|
||||
#ifndef DEBUG
|
||||
[eventDatabaseQueue inDatabase:^(FMDatabase *db) {
|
||||
db.logsErrors = NO;
|
||||
}];
|
||||
#endif
|
||||
});
|
||||
@@ -46,13 +46,13 @@ static NSString * const kEventsDatabaseName = @"events.db";
|
||||
static FMDatabaseQueue *ruleDatabaseQueue = nil;
|
||||
static dispatch_once_t ruleDatabaseToken;
|
||||
dispatch_once(&ruleDatabaseToken, ^{
|
||||
[self createDatabasePath];
|
||||
NSString *fullPath = [kDatabasePath stringByAppendingPathComponent:kRulesDatabaseName];
|
||||
ruleDatabaseQueue = [[FMDatabaseQueue alloc] initWithPath:fullPath];
|
||||
[self createDatabasePath];
|
||||
NSString *fullPath = [kDatabasePath stringByAppendingPathComponent:kRulesDatabaseName];
|
||||
ruleDatabaseQueue = [[FMDatabaseQueue alloc] initWithPath:fullPath];
|
||||
|
||||
#ifndef DEBUG
|
||||
[ruleDatabaseQueue inDatabase:^(FMDatabase *db) {
|
||||
db.logsErrors = NO;
|
||||
#ifndef DEBUG
|
||||
[ruleDatabaseQueue inDatabase:^(FMDatabase *db) {
|
||||
db.logsErrors = NO;
|
||||
}];
|
||||
#endif
|
||||
});
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
/// database exists and uses the latest schema.
|
||||
- (void)updateTableSchema {
|
||||
[self inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
||||
|
||||
int currentVersion = [db userVersion];
|
||||
int newVersion = [self initializeDatabase:db fromVersion:currentVersion];
|
||||
if (newVersion < 1) return;
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
///
|
||||
@interface SNTDriverManager : NSObject
|
||||
|
||||
///
|
||||
/// Handles locating and connecting to the driver. If driver is not loaded, will
|
||||
/// sleep until it is. If driver is loaded but connection fails (like if a client is
|
||||
/// already connected), will return nil.
|
||||
///
|
||||
- (instancetype)init;
|
||||
|
||||
///
|
||||
/// Handles requests from the kernel using the given block.
|
||||
/// @note Loops indefinitely unless there is an error trying to read data from the data queue.
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
@implementation SNTDriverManager
|
||||
|
||||
static const int MAX_DELAY = 15;
|
||||
|
||||
#pragma mark init/dealloc
|
||||
|
||||
- (instancetype)init {
|
||||
@@ -42,13 +44,15 @@
|
||||
}
|
||||
|
||||
// Locate driver. Wait for it if necessary.
|
||||
int delay = 1;
|
||||
do {
|
||||
CFRetain(classToMatch); // this ref is released by IOServiceGetMatchingService
|
||||
serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault, classToMatch);
|
||||
|
||||
if (!serviceObject) {
|
||||
LOGD(@"Waiting for Santa driver to become available");
|
||||
sleep(5);
|
||||
sleep(delay);
|
||||
if (delay < MAX_DELAY) delay *= 2;
|
||||
}
|
||||
} while (!serviceObject);
|
||||
CFRelease(classToMatch);
|
||||
@@ -104,8 +108,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// This will call clientMemoryForType() inside our user client class,
|
||||
// which activates the Kauth listeners.
|
||||
// This will call clientMemoryForType() inside our user client class.
|
||||
// The Kauth listener will start intercepting at this point and sending requests
|
||||
// to our queue.
|
||||
kr = IOConnectMapMemory(self.connection, kIODefaultMemoryType, mach_task_self(),
|
||||
&address, &size, kIOMapAnywhere);
|
||||
if (kr != kIOReturnSuccess) {
|
||||
|
||||
@@ -37,12 +37,10 @@
|
||||
@property SNTRuleTable *ruleTable;
|
||||
@property SNTEventTable *eventTable;
|
||||
@property SNTXPCConnection *notifierConnection;
|
||||
@property santa_clientmode_t operatingMode;
|
||||
|
||||
- (instancetype)initWithDriverManager:(SNTDriverManager *)driverManager
|
||||
ruleTable:(SNTRuleTable *)ruleTable
|
||||
eventTable:(SNTEventTable *)eventTable
|
||||
operatingMode:(santa_clientmode_t)operating_mode
|
||||
notifierConnection:(SNTXPCConnection *)notifierConn;
|
||||
|
||||
///
|
||||
@@ -53,11 +51,13 @@
|
||||
/// @param path the binary that's being executed
|
||||
/// @param userName the user who's executing the binary
|
||||
/// @param pid the process id being executed
|
||||
/// @param ppid the parent process id
|
||||
/// @param vnoteId the id of the vnode being executed
|
||||
///
|
||||
- (void)validateBinaryWithPath:(NSString *)path
|
||||
userName:(NSString *)userName
|
||||
pid:(NSNumber *)pid
|
||||
ppid:(NSNumber *)ppid
|
||||
vnodeId:(uint64_t)vnodeId;
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCodesignChecker.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDriverManager.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTEventTable.h"
|
||||
@@ -37,14 +38,12 @@
|
||||
- (instancetype)initWithDriverManager:(SNTDriverManager *)driverManager
|
||||
ruleTable:(SNTRuleTable *)ruleTable
|
||||
eventTable:(SNTEventTable *)eventTable
|
||||
operatingMode:(santa_clientmode_t)operatingMode
|
||||
notifierConnection:(SNTXPCConnection *)notifier {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_driverManager = driverManager;
|
||||
_ruleTable = ruleTable;
|
||||
_eventTable = eventTable;
|
||||
_operatingMode = operatingMode;
|
||||
_notifierConnection = notifier;
|
||||
LOGI(@"Log format: Decision (A|D), Reason (B|C|S|?), SHA-256, Path, Cert SHA-256, Cert CN");
|
||||
|
||||
@@ -61,6 +60,7 @@
|
||||
- (void)validateBinaryWithPath:(NSString *)path
|
||||
userName:(NSString *)userName
|
||||
pid:(NSNumber *)pid
|
||||
ppid:(NSNumber *)ppid
|
||||
vnodeId:(uint64_t)vnodeId {
|
||||
SNTFileInfo *binInfo = [[SNTFileInfo alloc] initWithPath:path];
|
||||
NSString *sha256 = [binInfo SHA256];
|
||||
@@ -101,7 +101,9 @@
|
||||
}
|
||||
|
||||
// Step 5 - log to database and potentially alert user
|
||||
if (respondedAction == ACTION_RESPOND_CHECKBW_DENY || !rule) {
|
||||
if (respondedAction == ACTION_RESPOND_CHECKBW_DENY ||
|
||||
!rule ||
|
||||
[[SNTConfigurator configurator] logAllEvents]) {
|
||||
SNTStoredEvent *se = [[SNTStoredEvent alloc] init];
|
||||
se.fileSHA256 = sha256;
|
||||
se.filePath = path;
|
||||
@@ -121,6 +123,7 @@
|
||||
se.occurrenceDate = [[NSDate alloc] init];
|
||||
se.decision = [self eventStateForDecision:respondedAction type:rule.type];
|
||||
se.pid = pid;
|
||||
se.ppid = ppid;
|
||||
|
||||
NSArray *loggedInUsers, *currentSessions;
|
||||
[self loggedInUsers:&loggedInUsers sessions:¤tSessions];
|
||||
@@ -263,7 +266,7 @@
|
||||
}
|
||||
|
||||
- (santa_action_t)defaultDecision {
|
||||
switch (self.operatingMode) {
|
||||
switch ([[SNTConfigurator configurator] clientMode]) {
|
||||
case CLIENTMODE_MONITOR:
|
||||
return ACTION_RESPOND_CHECKBW_ALLOW;
|
||||
case CLIENTMODE_LOCKDOWN:
|
||||
@@ -305,12 +308,12 @@
|
||||
sessionName = [NSString stringWithFormat:@"%s@%s", nxt->ut_user, nxt->ut_line];
|
||||
}
|
||||
|
||||
if (userName && ![userName isEqual:@""]) {
|
||||
loggedInUsers[userName] = @"";
|
||||
if ([userName length] > 0) {
|
||||
loggedInUsers[userName] = [NSNull null];
|
||||
}
|
||||
|
||||
if (sessionName && ![sessionName isEqual:@":"]) {
|
||||
loggedInHosts[sessionName] = @"";
|
||||
if ([sessionName length] > 1) {
|
||||
loggedInHosts[sessionName] = [NSNull null];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
/// transaction will abort if any rule fails to add.
|
||||
///
|
||||
/// @param rules Array of SNTRule's to add.
|
||||
/// @param cleanslate If true, remove all rules before adding the new rules.
|
||||
/// @return YES if all rules were added successfully.
|
||||
///
|
||||
- (BOOL)addRules:(NSArray *)rules;
|
||||
- (BOOL)addRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -119,10 +119,14 @@
|
||||
|
||||
#pragma mark Adding
|
||||
|
||||
- (BOOL)addRules:(NSArray *)rules {
|
||||
- (BOOL)addRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate {
|
||||
__block BOOL failed = NO;
|
||||
|
||||
[self inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
||||
if (cleanSlate) {
|
||||
[db executeUpdate:@"DELETE FROM rules"];
|
||||
}
|
||||
|
||||
for (SNTRule *rule in rules) {
|
||||
if (![rule isKindOfClass:[SNTRule class]] ||
|
||||
!rule.shasum || rule.shasum.length == 0 ||
|
||||
|
||||
12
Tests/LogicTests/Resources/dn.plist
Normal file
12
Tests/LogicTests/Resources/dn.plist
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<array>
|
||||
<data>
|
||||
MIGcMQswCQYDVQQGEwJVUzERMA8GA1UECAwIVGhlIE1vb24xEjAQBgNVBAcMCU1vb24g
|
||||
QmFzZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMSkwJwYDVQQLDCBB
|
||||
d2Vzb21lIEF1dGhlbnRpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAwwPYXV0aC5zZXJ2
|
||||
ZXIuY29t
|
||||
</data>
|
||||
</array>
|
||||
</plist>
|
||||
@@ -80,9 +80,11 @@
|
||||
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");
|
||||
@@ -97,6 +99,7 @@
|
||||
@"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 {
|
||||
@@ -219,14 +222,18 @@
|
||||
(void)sut.orgName;
|
||||
(void)sut.issuerCommonName;
|
||||
(void)sut.validFrom;
|
||||
(void)sut.countryName;
|
||||
(void)sut.issuerCountryName;
|
||||
|
||||
// Now break some of the properties
|
||||
OCMStub([sutMock x509ValueForLabel:OCMOCK_ANY fromDictionary:OCMOCK_ANY]);
|
||||
OCMStub([sutMock dateForX509Key:OCMOCK_ANY]);
|
||||
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
|
||||
|
||||
@@ -33,6 +33,17 @@
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testAllFields {
|
||||
NSString *file = [[NSBundle bundleForClass:[self class]] pathForResource:@"dn" ofType:@"plist"];
|
||||
NSArray *distinguishedNames = [NSArray arrayWithContentsOfFile:file];
|
||||
|
||||
SNTDERDecoder *sut = [[SNTDERDecoder alloc] initWithData:[distinguishedNames firstObject]];
|
||||
XCTAssertEqualObjects(sut.commonName, @"auth.server.com");
|
||||
XCTAssertEqualObjects(sut.organizationName, @"Internet Widgits Pty Ltd");
|
||||
XCTAssertEqualObjects(sut.organizationalUnit, @"Awesome Authentication Authority");
|
||||
XCTAssertEqualObjects(sut.countryName, @"US");
|
||||
}
|
||||
|
||||
- (void)testOIDDecoding {
|
||||
unsigned char oidBytes1[] = {0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x14};
|
||||
NSString *oidStr = [SNTDERDecoder decodeOIDWithBytes:oidBytes1 length:sizeof(oidBytes1)];
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCodesignChecker.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDriverManager.h"
|
||||
#import "SNTEventTable.h"
|
||||
#import "SNTFileInfo.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
@end
|
||||
|
||||
@interface SNTExecutionControllerTest : XCTestCase
|
||||
@property id mockConfigurator;
|
||||
@property id mockCodesignChecker;
|
||||
@property id mockDriverManager;
|
||||
@property id mockFileInfo;
|
||||
@@ -47,15 +49,26 @@
|
||||
fclose(stdout);
|
||||
|
||||
self.mockCodesignChecker = OCMClassMock([SNTCodesignChecker class]);
|
||||
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY])
|
||||
.andReturn(self.mockCodesignChecker);
|
||||
|
||||
self.mockConfigurator = OCMClassMock([SNTConfigurator class]);
|
||||
OCMStub([self.mockConfigurator configurator]).andReturn(self.mockConfigurator);
|
||||
OCMStub([self.mockConfigurator configurator]).andReturn(self.mockConfigurator);
|
||||
|
||||
self.mockDriverManager = OCMClassMock([SNTDriverManager class]);
|
||||
self.mockFileInfo = OCMClassMock([SNTFileInfo class]);
|
||||
|
||||
self.mockFileInfo = OCMClassMock([SNTFileInfo class]);
|
||||
OCMStub([self.mockFileInfo alloc]).andReturn(self.mockFileInfo);
|
||||
OCMStub([self.mockFileInfo initWithPath:OCMOCK_ANY]).andReturn(self.mockFileInfo);
|
||||
|
||||
self.mockRuleDatabase = OCMClassMock([SNTRuleTable class]);
|
||||
self.mockEventDatabase = OCMClassMock([SNTEventTable class]);
|
||||
|
||||
self.sut = [[SNTExecutionController alloc] initWithDriverManager:self.mockDriverManager
|
||||
ruleTable:self.mockRuleDatabase
|
||||
eventTable:self.mockEventDatabase
|
||||
operatingMode:CLIENTMODE_MONITOR
|
||||
notifierConnection:nil];
|
||||
}
|
||||
|
||||
@@ -73,13 +86,16 @@
|
||||
id mockSut = OCMPartialMock(self.sut);
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(YES);
|
||||
|
||||
OCMExpect([self.mockFileInfo SHA256]).andReturn(@"a");
|
||||
|
||||
SNTRule *rule = [[SNTRule alloc] init];
|
||||
rule.state = RULESTATE_WHITELIST;
|
||||
OCMStub([self.mockRuleDatabase binaryRuleForSHA256:@"a"]).andReturn(rule);
|
||||
OCMExpect([self.mockRuleDatabase binaryRuleForSHA256:@"a"]).andReturn(rule);
|
||||
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_ALLOW
|
||||
@@ -90,17 +106,16 @@
|
||||
id mockSut = OCMPartialMock(self.sut);
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(YES);
|
||||
|
||||
[[[self.mockFileInfo stub] andReturn:self.mockFileInfo] alloc];
|
||||
(void)[[[self.mockFileInfo stub] andReturn:self.mockFileInfo] initWithPath:[OCMArg any]];
|
||||
[[[self.mockFileInfo stub] andReturn:@"a"] SHA256];
|
||||
OCMExpect([self.mockFileInfo SHA256]).andReturn(@"a");
|
||||
|
||||
SNTRule *rule = [[SNTRule alloc] init];
|
||||
rule.state = RULESTATE_BLACKLIST;
|
||||
OCMStub([self.mockRuleDatabase binaryRuleForSHA256:@"a"]).andReturn(rule);
|
||||
OCMExpect([self.mockRuleDatabase binaryRuleForSHA256:@"a"]).andReturn(rule);
|
||||
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_DENY
|
||||
@@ -112,19 +127,17 @@
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(YES);
|
||||
|
||||
id cert = OCMClassMock([SNTCertificate class]);
|
||||
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY])
|
||||
.andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker leafCertificate]).andReturn(cert);
|
||||
OCMStub([cert SHA256]).andReturn(@"a");
|
||||
OCMExpect([self.mockCodesignChecker leafCertificate]).andReturn(cert);
|
||||
OCMExpect([cert SHA256]).andReturn(@"a");
|
||||
|
||||
SNTRule *rule = [[SNTRule alloc] init];
|
||||
rule.state = RULESTATE_WHITELIST;
|
||||
OCMStub([self.mockRuleDatabase certificateRuleForSHA256:@"a"]).andReturn(rule);
|
||||
OCMExpect([self.mockRuleDatabase certificateRuleForSHA256:@"a"]).andReturn(rule);
|
||||
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_ALLOW
|
||||
@@ -136,19 +149,17 @@
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(YES);
|
||||
|
||||
id cert = OCMClassMock([SNTCertificate class]);
|
||||
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY])
|
||||
.andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker leafCertificate]).andReturn(cert);
|
||||
OCMStub([cert SHA256]).andReturn(@"a");
|
||||
OCMExpect([self.mockCodesignChecker leafCertificate]).andReturn(cert);
|
||||
OCMExpect([cert SHA256]).andReturn(@"a");
|
||||
|
||||
SNTRule *rule = [[SNTRule alloc] init];
|
||||
rule.state = RULESTATE_BLACKLIST;
|
||||
OCMStub([self.mockRuleDatabase certificateRuleForSHA256:@"a"]).andReturn(rule);
|
||||
OCMExpect([self.mockRuleDatabase certificateRuleForSHA256:@"a"]).andReturn(rule);
|
||||
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_DENY
|
||||
@@ -159,15 +170,20 @@
|
||||
id mockSut = OCMPartialMock(self.sut);
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(YES);
|
||||
|
||||
[self.sut setOperatingMode:CLIENTMODE_MONITOR];
|
||||
[self.sut validateBinaryWithPath:@"/a/file" userName:@"nobody" pid:@(12) vnodeId:1234];
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_ALLOW
|
||||
forVnodeID:1234]);
|
||||
|
||||
[self.sut setOperatingMode:CLIENTMODE_LOCKDOWN];
|
||||
OCMExpect([self.mockConfigurator clientMode]).andReturn(CLIENTMODE_MONITOR);
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_ALLOW
|
||||
forVnodeID:1234]);
|
||||
|
||||
OCMExpect([self.mockConfigurator clientMode]).andReturn(CLIENTMODE_LOCKDOWN);
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(12)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_DENY
|
||||
forVnodeID:1234]);
|
||||
@@ -177,8 +193,12 @@
|
||||
id mockSut = OCMPartialMock(self.sut);
|
||||
OCMStub([mockSut fileIsInScope:OCMOCK_ANY]).andReturn(NO);
|
||||
|
||||
[self.sut setOperatingMode:CLIENTMODE_LOCKDOWN];
|
||||
[self.sut validateBinaryWithPath:@"/a/file" userName:@"nobody" pid:@(24) vnodeId:1234];
|
||||
OCMExpect([self.mockConfigurator clientMode]).andReturn(CLIENTMODE_LOCKDOWN);
|
||||
[self.sut validateBinaryWithPath:@"/a/file"
|
||||
userName:@"nobody"
|
||||
pid:@(24)
|
||||
ppid:@(1)
|
||||
vnodeId:1234];
|
||||
OCMVerify([self.mockDriverManager postToKernelAction:ACTION_RESPOND_CHECKBW_ALLOW
|
||||
forVnodeID:1234]);
|
||||
}
|
||||
|
||||
132
Tests/LogicTests/SNTFileWatcherTest.m
Normal file
132
Tests/LogicTests/SNTFileWatcherTest.m
Normal file
@@ -0,0 +1,132 @@
|
||||
/// 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 "SNTFileWatcher.h"
|
||||
|
||||
@interface SNTFileWatcherTest : XCTestCase
|
||||
@property NSFileManager *fm;
|
||||
@property NSString *file;
|
||||
@end
|
||||
|
||||
@implementation SNTFileWatcherTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.fm = [NSFileManager defaultManager];
|
||||
self.file = @"/tmp/SNTFileWatcherTest_File";
|
||||
[self createFile];
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[self deleteFile];
|
||||
usleep(10000);
|
||||
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)createFile {
|
||||
[self.fm createFileAtPath:self.file contents:nil attributes:nil];
|
||||
}
|
||||
|
||||
- (void)deleteFile {
|
||||
[self.fm removeItemAtPath:self.file error:NULL];
|
||||
}
|
||||
|
||||
- (void)testPlainInit {
|
||||
XCTAssertThrows([[SNTFileWatcher alloc] init]);
|
||||
}
|
||||
|
||||
- (void)testInitFileExists {
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^{
|
||||
[exp fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testInitNewFile {
|
||||
[self deleteFile];
|
||||
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^{
|
||||
[exp fulfill];
|
||||
}];
|
||||
|
||||
[self createFile];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileChanged {
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Changed: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^{
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if ([d isEqual:@"0x8BADF00D"]) {
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
[[@"0x8BADF00D" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:NO];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileReplaced {
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Replaced: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^{
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if ([d isEqual:@"0xFACEFEED"]) {
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
[[@"0xFACEFEED" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:YES];
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileExtended {
|
||||
int fd = open(self.file.fileSystemRepresentation, O_WRONLY);
|
||||
write(fd, "0xDEAD", 6);
|
||||
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Extended: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^{
|
||||
int file = open(self.file.fileSystemRepresentation, O_RDONLY);
|
||||
char fileData[10];
|
||||
read(file, fileData, 10);
|
||||
|
||||
if (strncmp(fileData, "0xDEADBEEF", 10) == 0) {
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
write(fd, "BEEF", 4);
|
||||
close(fd);
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
}
|
||||
|
||||
- (void)testInitClient {
|
||||
OCMStub([self.mockConnection initWithMachServiceName:@"TestClient"
|
||||
options:NSXPCConnectionPrivileged])
|
||||
OCMExpect([self.mockConnection initWithMachServiceName:@"TestClient"
|
||||
options:NSXPCConnectionPrivileged])
|
||||
.andReturn(self.mockConnection);
|
||||
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initClientWithName:@"TestClient"
|
||||
@@ -63,14 +63,14 @@
|
||||
}
|
||||
|
||||
- (void)testInitServer {
|
||||
OCMStub([self.mockListener initWithMachServiceName:@"TestServer"]).andReturn(self.mockListener);
|
||||
OCMExpect([self.mockListener initWithMachServiceName:@"TestServer"]).andReturn(self.mockListener);
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initServerWithName:@"TestServer"];
|
||||
XCTAssertNotNil(sut);
|
||||
OCMVerifyAll(self.mockListener);
|
||||
}
|
||||
|
||||
- (void)testResume {
|
||||
OCMStub([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
OCMExpect([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initServerWithName:@"TestServer"];
|
||||
|
||||
[sut resume];
|
||||
@@ -80,7 +80,7 @@
|
||||
}
|
||||
|
||||
- (void)testListenerShouldAcceptNewConnection {
|
||||
OCMStub([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
OCMExpect([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initServerWithName:@"TestServer"];
|
||||
|
||||
XCTAssertTrue([sut listener:self.mockListener shouldAcceptNewConnection:self.mockConnection]);
|
||||
@@ -93,16 +93,16 @@
|
||||
}
|
||||
|
||||
- (void)testIsConnectionValidFalse {
|
||||
OCMStub([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
OCMExpect([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initServerWithName:@"TestServer"];
|
||||
|
||||
[sut setCurrentConnection:self.mockConnection];
|
||||
|
||||
OCMStub([self.mockConnection processIdentifier]).andReturn(1);
|
||||
OCMExpect([self.mockConnection processIdentifier]).andReturn(1);
|
||||
|
||||
id mockCodesignChecker = OCMClassMock([SNTCodesignChecker class]);
|
||||
OCMStub([mockCodesignChecker alloc]).andReturn(mockCodesignChecker);
|
||||
OCMStub([mockCodesignChecker signingInformationMatches:OCMOCK_ANY]).andReturn(NO);
|
||||
OCMExpect([mockCodesignChecker alloc]).andReturn(mockCodesignChecker);
|
||||
OCMExpect([mockCodesignChecker signingInformationMatches:OCMOCK_ANY]).andReturn(NO);
|
||||
|
||||
[sut isConnectionValidWithBlock:^(BOOL input) {
|
||||
XCTAssertFalse(input);
|
||||
@@ -115,13 +115,13 @@
|
||||
}
|
||||
|
||||
- (void)testIsConnectionValidTrue {
|
||||
OCMStub([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
OCMExpect([self.mockListener initWithMachServiceName:OCMOCK_ANY]).andReturn(self.mockListener);
|
||||
SNTXPCConnection *sut = [[SNTXPCConnection alloc] initServerWithName:@"TestServer"];
|
||||
|
||||
[sut setCurrentConnection:self.mockConnection];
|
||||
|
||||
pid_t mypid = [[NSProcessInfo processInfo] processIdentifier];
|
||||
OCMStub([self.mockConnection processIdentifier]).andReturn(mypid);
|
||||
OCMExpect([self.mockConnection processIdentifier]).andReturn(mypid);
|
||||
|
||||
[sut isConnectionValidWithBlock:^(BOOL input) {
|
||||
XCTAssertTrue(input);
|
||||
|
||||
Reference in New Issue
Block a user