mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
184 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
a59d2aa8a9 | ||
|
|
d88fa4ecfe | ||
|
|
4df93bfe6c | ||
|
|
08ca3c9d95 | ||
|
|
3423026a43 | ||
|
|
e574621911 | ||
|
|
f1a3246eb9 | ||
|
|
eeda832fae | ||
|
|
40af338af2 | ||
|
|
8a4b2a8480 | ||
|
|
912f3aa0e1 | ||
|
|
e7cb5703f2 | ||
|
|
6fb81471e0 | ||
|
|
54ffbf40d6 | ||
|
|
101c9d2b1f | ||
|
|
ce9af3d019 | ||
|
|
d11b137f9b | ||
|
|
9d1117b0c7 | ||
|
|
ee9a7f635a | ||
|
|
63c6e4f852 | ||
|
|
af63d036de | ||
|
|
b728ea3077 | ||
|
|
a98bd00492 | ||
|
|
6aeae5f1b6 | ||
|
|
7a03183cf0 | ||
|
|
6b743015a0 | ||
|
|
b095625972 | ||
|
|
98adf9c2c1 | ||
|
|
c447eb959b | ||
|
|
801d2b241a | ||
|
|
42684387c5 | ||
|
|
a66255aa8f | ||
|
|
30d335658c | ||
|
|
20a7d6074f | ||
|
|
f8273555a4 | ||
|
|
a607136a0d | ||
|
|
4b166f4485 | ||
|
|
f1f2913529 | ||
|
|
1117b28d8d | ||
|
|
72811e5546 | ||
|
|
3fefa7676f | ||
|
|
75883af800 | ||
|
|
22e5ffa1f1 | ||
|
|
8b671ea2cd | ||
|
|
ecbd92646d | ||
|
|
b946598f7b | ||
|
|
b30696b8a3 | ||
|
|
ae74a61a7e | ||
|
|
2ae9229a6b | ||
|
|
95a334dbaf | ||
|
|
6335a02404 | ||
|
|
5c9cceec35 | ||
|
|
71b08307a3 | ||
|
|
180c8f2226 | ||
|
|
2305ec578c | ||
|
|
2f735dc716 | ||
|
|
afca026c12 | ||
|
|
1447fd8789 | ||
|
|
ccd871cfdd | ||
|
|
407466cd5f | ||
|
|
ba9340d30d | ||
|
|
a7715e3ce2 | ||
|
|
1a8cd79bf9 | ||
|
|
a560c84cdc | ||
|
|
4e0cfeb16d | ||
|
|
195ba4d918 | ||
|
|
7458896a2a | ||
|
|
a78f2b37ee | ||
|
|
d3c0d409ab | ||
|
|
71833da8f4 | ||
|
|
10892691e8 | ||
|
|
5139fe692c | ||
|
|
7cdfda187e | ||
|
|
d4538b4f7c | ||
|
|
c885dbdd4f | ||
|
|
1bfe8feeb1 | ||
|
|
caaa7e60c3 | ||
|
|
21bf445f46 | ||
|
|
685641bb5d | ||
|
|
53c00ef61e | ||
|
|
8ec7f28f94 | ||
|
|
09d71f8790 | ||
|
|
e8f298aa38 | ||
|
|
172a260cdc | ||
|
|
d47770804e | ||
|
|
b4b899cf37 | ||
|
|
df59825c57 | ||
|
|
e959e42282 | ||
|
|
86cd6aa133 | ||
|
|
de61869b01 | ||
|
|
c9a6b59a43 | ||
|
|
76ae6adced | ||
|
|
6b177933e2 | ||
|
|
06c95e9121 | ||
|
|
dbbdfb1965 | ||
|
|
2d927175e0 | ||
|
|
642b69bde2 | ||
|
|
16ca9b85ab | ||
|
|
cbf16d140b | ||
|
|
bf84a86450 | ||
|
|
1503f8658d | ||
|
|
c8bcf3ba2c | ||
|
|
9d1c850b91 | ||
|
|
fe90353c75 | ||
|
|
2d1941dcff | ||
|
|
546b2f1383 | ||
|
|
4509cd5c0b | ||
|
|
9a423f1b06 | ||
|
|
292c51e8a5 | ||
|
|
c2f04c50a5 | ||
|
|
65cb531ac8 | ||
|
|
373b49cee4 | ||
|
|
654aa7cf2d | ||
|
|
6174f80abd | ||
|
|
7268de352f | ||
|
|
f046711fb0 | ||
|
|
fac4e68adf | ||
|
|
8693fad2c9 | ||
|
|
bca08ad359 | ||
|
|
e32b4e2350 | ||
|
|
97a5755c3d | ||
|
|
17f102662a | ||
|
|
f47ce3d2bc |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,8 @@
|
||||
.DS_Store
|
||||
Build
|
||||
Dist
|
||||
Pods
|
||||
Santa.xcodeproj/xcuserdata
|
||||
Santa.xcodeproj/project.xcworkspace
|
||||
Santa.xcworkspace/xcuserdata
|
||||
Santa.xcworkspace/xcshareddata
|
||||
|
||||
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
language: objective-c
|
||||
|
||||
before_install:
|
||||
- gem install cocoapods
|
||||
- brew update
|
||||
- brew upgrade xctool
|
||||
|
||||
script:
|
||||
- xctool -workspace Santa.xcworkspace -scheme All build test CODE_SIGN_IDENTITY=''
|
||||
@@ -25,6 +25,12 @@ tests beforehand, which you can do with the following commands:
|
||||
rake tests:logic
|
||||
rake tests:kernel # only necessary if you're changing the kext code
|
||||
```
|
||||
### Code Style
|
||||
|
||||
All code submissions should try to match the surrounding code. Wherever possible,
|
||||
code should adhere to either the
|
||||
[Google Objective-C Style Guide](http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml)
|
||||
or the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html).
|
||||
|
||||
### The small print
|
||||
Contributions made by corporations are covered by a different agreement than
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
# Copy this file to /etc/asl to log all messages from santa-driver to the log file
|
||||
? [S= Message santa-driver:] file /var/log/santa.log claim only format="[$((Time)(utc.3))] $Message"
|
||||
? [S= Message santa-driver:] claim only
|
||||
? [S= Message santa-driver:] file /var/log/santa.log format="[$((Time)(utc.3))] $Message"
|
||||
> /var/log/santa.log mode=0644 rotate=seq compress file_max=5M all_max=100M
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
<array>
|
||||
<string>/Applications/Santa.app/Contents/MacOS/Santa</string>
|
||||
</array>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/santa.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/santa.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
14
Podfile
14
Podfile
@@ -1,9 +1,21 @@
|
||||
platform :osx, "10.8"
|
||||
platform :osx, "10.9"
|
||||
|
||||
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
|
||||
|
||||
16
Podfile.lock
16
Podfile.lock
@@ -1,17 +1,17 @@
|
||||
PODS:
|
||||
- FMDB (2.4):
|
||||
- FMDB/standard (= 2.4)
|
||||
- FMDB/common (2.4)
|
||||
- FMDB/standard (2.4):
|
||||
- FMDB (2.5):
|
||||
- FMDB/standard (= 2.5)
|
||||
- FMDB/common (2.5)
|
||||
- FMDB/standard (2.5):
|
||||
- FMDB/common
|
||||
- OCMock (3.1.1)
|
||||
- OCMock (3.1.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- FMDB
|
||||
- OCMock
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FMDB: 0b2fa25e5264ef177973c0cb8c02c711107979aa
|
||||
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
|
||||
FMDB: 96e8f1bcc1329e269330f99770ad4285d9003e52
|
||||
OCMock: a10ea9f0a6e921651f96f78b6faee95ebc813b92
|
||||
|
||||
COCOAPODS: 0.35.0
|
||||
COCOAPODS: 0.36.1
|
||||
|
||||
31
README.md
31
README.md
@@ -1,4 +1,4 @@
|
||||
Santa
|
||||
Santa [](https://travis-ci.org/google/santa)
|
||||
=====
|
||||
|
||||
Santa is a binary whitelisting/blacklisting system for Mac OS X. It consists of
|
||||
@@ -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
|
||||
@@ -112,16 +105,22 @@ be shown when loading the kext for the first time. In 10.10 this is a hard error
|
||||
and the kext will not load at all unless the machine is booted with a debug
|
||||
boot-arg.
|
||||
|
||||
There are two possible solutions for this:
|
||||
There are two possible solutions for this, for distribution purposes:
|
||||
|
||||
1) Use a pre-built, pre-signed version of the kext that we supply. Each time
|
||||
changes are made to the kext code we will update the pre-built version that you
|
||||
can make use of. This doesn't prevent you from making changes to the non-kext
|
||||
parts of Santa and distributing those. If you make changes to the kext and make
|
||||
a pull request, we can merge them in and distribute a new version of the
|
||||
pre-signed kext.
|
||||
1) Use a [pre-built, pre-signed version](https://github.com/google/santa/releases)
|
||||
of the kext that we supply. Each time changes are made to the kext code we will
|
||||
update the pre-built version that you can make use of. This doesn't prevent you
|
||||
from making changes to the non-kext parts of Santa and distributing those.
|
||||
If you make changes to the kext and make a pull request, we can merge them in
|
||||
and distribute a new version of the pre-signed kext.
|
||||
|
||||
2) Apply for your own [kext signing certificate](https://developer.apple.com/contact/kext/).
|
||||
Apple will only grant this for broad distribution within an organization, they
|
||||
won't issue them just for testing purposes.
|
||||
|
||||
If you just want to locally test changes to the kext code, you should enable
|
||||
kext-dev mode, instructions for which can be found on the Apple developer site.
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
76
Rakefile
76
Rakefile
@@ -2,17 +2,20 @@ require 'timeout'
|
||||
|
||||
WORKSPACE = 'Santa.xcworkspace'
|
||||
DEFAULT_SCHEME = 'All'
|
||||
OUTPUT_PATH = 'build'
|
||||
PLISTS = ['Source/SantaGUI/Resources/Santa-Info.plist',
|
||||
'Source/santad/Resources/santad-Info.plist',
|
||||
'Source/santa-driver/Resources/santa-driver-Info.plist',
|
||||
'Source/santactl/Resources/santactl-Info.plist']
|
||||
XCODE_DEFAULTS = "-workspace #{WORKSPACE} -scheme #{DEFAULT_SCHEME} -derivedDataPath #{OUTPUT_PATH} -parallelizeTargets"
|
||||
OUTPUT_PATH = 'Build'
|
||||
DIST_PATH = 'Dist'
|
||||
BINARIES = ['Santa.app', 'santa-driver.kext', 'santad', 'santactl']
|
||||
XCTOOL_DEFAULTS = "-workspace #{WORKSPACE}"
|
||||
XCODE_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?
|
||||
@@ -43,7 +46,7 @@ end
|
||||
|
||||
task :init do
|
||||
unless File.exists?(WORKSPACE) and File.exists?('Pods')
|
||||
puts "Workspace is missing, running 'pod install'"
|
||||
puts "Pods missing, running 'pod install'"
|
||||
system "pod install" or raise "CocoaPods is not installed. Install with 'sudo gem install cocoapods'"
|
||||
end
|
||||
end
|
||||
@@ -58,8 +61,9 @@ end
|
||||
desc "Clean"
|
||||
task :clean => :init do
|
||||
puts "Cleaning"
|
||||
run_and_output_on_fail("xcodebuild #{XCODE_DEFAULTS} clean")
|
||||
system "xcodebuild #{XCODE_DEFAULTS} -scheme All clean"
|
||||
FileUtils.rm_rf(OUTPUT_PATH)
|
||||
FileUtils.rm_rf(DIST_PATH)
|
||||
end
|
||||
|
||||
# Build
|
||||
@@ -77,7 +81,11 @@ namespace :build do
|
||||
task :build, [:configuration] => :init do |t, args|
|
||||
config = args[:configuration]
|
||||
puts "Building with configuration: #{config}"
|
||||
run_and_output_on_fail("xcodebuild #{XCODE_DEFAULTS} -configuration #{config} build")
|
||||
if xctool_available
|
||||
system "xctool #{XCTOOL_DEFAULTS} -scheme All -configuration #{config} build"
|
||||
else
|
||||
system "xcodebuild #{XCODE_DEFAULTS} -scheme All -configuration #{config} build"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,12 +118,38 @@ namespace :install do
|
||||
end
|
||||
end
|
||||
|
||||
# Dist
|
||||
task :dist do
|
||||
desc "Create distribution folder"
|
||||
|
||||
Rake::Task['build:build'].invoke("Release")
|
||||
|
||||
FileUtils.rm_rf(DIST_PATH)
|
||||
|
||||
FileUtils.mkdir_p("#{DIST_PATH}/binaries")
|
||||
FileUtils.mkdir_p("#{DIST_PATH}/conf")
|
||||
FileUtils.mkdir_p("#{DIST_PATH}/dsym")
|
||||
|
||||
BINARIES.each do |x|
|
||||
FileUtils.cp_r("#{OUTPUT_PATH}/Products/Release/#{x}", "#{DIST_PATH}/binaries")
|
||||
FileUtils.cp_r("#{OUTPUT_PATH}/Products/Release/#{x}.dSYM", "#{DIST_PATH}/dsym")
|
||||
end
|
||||
|
||||
Dir.glob("Conf/*") {|x| FileUtils.cp(x, "#{DIST_PATH}/conf")}
|
||||
|
||||
puts "Distribution folder created"
|
||||
end
|
||||
|
||||
# Tests
|
||||
namespace :tests do
|
||||
desc "Tests: Logic"
|
||||
task :logic => [:init] do
|
||||
puts "Running logic tests"
|
||||
run_and_output_with_color("xcodebuild #{XCODE_DEFAULTS} test")
|
||||
if xctool_available
|
||||
system "xctool #{XCTOOL_DEFAULTS} -scheme LogicTests test"
|
||||
else
|
||||
system "xcodebuild #{XCODE_DEFAULTS} -scheme LogicTests test"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Tests: Kernel"
|
||||
@@ -144,7 +178,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
|
||||
@@ -188,23 +222,3 @@ namespace :reload do
|
||||
Rake::Task['load'].invoke()
|
||||
end
|
||||
end
|
||||
|
||||
# Versioning
|
||||
desc "Update version, version should be of the form rake version[\\d{1,4}.\\d{1,2}(?:.\\d{1,2})?]"
|
||||
task :version, :version do |t, args|
|
||||
response = args[:version]
|
||||
|
||||
unless response =~ /^\d{1,4}\.\d{1,2}(?:\.\d{1,2})?$/
|
||||
raise "Version number must be of form: xxxx.xx[.xx]. E.g: rake version[1.0.2], rake version[1.7]"
|
||||
end
|
||||
|
||||
system "sed -i -e 's/MODULE_VERSION = .*;/MODULE_VERSION = #{response};/g' Santa.xcodeproj/project.pbxproj"
|
||||
|
||||
PLISTS.each do |plist|
|
||||
system "defaults write $PWD/#{plist} CFBundleVersion #{response}"
|
||||
system "defaults write $PWD/#{plist} CFBundleShortVersionString #{response}"
|
||||
system "plutil -convert xml1 $PWD/#{plist}"
|
||||
end
|
||||
|
||||
puts "Updated version to #{response}"
|
||||
end
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
0D1AF478187C7A2C00D3298D /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
|
||||
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */; };
|
||||
0D1B477119A53419008CADD3 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D1B476F19A53419008CADD3 /* AboutWindow.xib */; };
|
||||
0D260DAE18B68E12002A0B55 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D260DAD18B68E12002A0B55 /* XCTest.framework */; };
|
||||
0D260DC118B69078002A0B55 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D260DC018B69078002A0B55 /* Security.framework */; };
|
||||
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 */; };
|
||||
@@ -71,13 +71,14 @@
|
||||
0D3AFBF818FB4C870087BCEE /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0D416401191974F1006A356A /* SNTCommandSyncStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncStatus.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 */; };
|
||||
0D42D2B819D2042900955F08 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
|
||||
0D42D2B919D2042900955F08 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
|
||||
0D4644C5182AF81700098690 /* SantaDecisionManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0D4644C3182AF81700098690 /* SantaDecisionManager.cc */; };
|
||||
0D4644C6182AF81700098690 /* SantaDecisionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D4644C4182AF81700098690 /* SantaDecisionManager.h */; };
|
||||
0D4A5007176A4602004F63BF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D4A5006176A4602004F63BF /* Security.framework */; };
|
||||
0D54E0B11976F8D3000BB59F /* SNTBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */; };
|
||||
0D54E0B11976F8D3000BB59F /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
|
||||
0D59C0E417710E6000748EBF /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
|
||||
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
|
||||
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
|
||||
@@ -88,7 +89,6 @@
|
||||
0D6FDC8518C68E500044685C /* GIAG2.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0D6FDC8418C68E500044685C /* GIAG2.pem */; };
|
||||
0D6FDC8718C6913D0044685C /* apple.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0D6FDC8618C6913D0044685C /* apple.pem */; };
|
||||
0D6FDC8C18C69AF90044685C /* SNTCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1AF476187C7A2C00D3298D /* SNTCertificate.m */; };
|
||||
0D6FDC8F18C7F0200044685C /* SNTNotificationMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DBE65F018BEA3CC00AC994C /* SNTNotificationMessage.m */; };
|
||||
0D6FDC9618C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
|
||||
0D6FDC9718C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
|
||||
0D7A7AF3174FCF4C00B77646 /* SantaMessage.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0D7A7AF1174FCF4C00B77646 /* SantaMessage.cc */; };
|
||||
@@ -97,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 */; };
|
||||
@@ -108,16 +112,16 @@
|
||||
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 */; };
|
||||
0DBE65F118BEA3CC00AC994C /* SNTNotificationMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DBE65F018BEA3CC00AC994C /* SNTNotificationMessage.m */; };
|
||||
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D870192160180078A5C0 /* SNTCommandSyncLogUpload.m */; };
|
||||
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
|
||||
0DCD5FBF1909D64A006B445C /* SNTCommandBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD5FBE1909D64A006B445C /* SNTCommandBinaryInfo.m */; };
|
||||
0DCD6042190ACCB8006B445C /* SNTBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */; };
|
||||
0DCD6043190ACCB8006B445C /* SNTBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */; };
|
||||
0DCD6044190ACCB8006B445C /* SNTBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */; };
|
||||
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
|
||||
0DCD6043190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
|
||||
0DCD6044190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
|
||||
0DCD604B19105433006B445C /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
|
||||
0DCD604D19105433006B445C /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
|
||||
0DCD604F19115A06006B445C /* SNTXPCNotifierInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604E19115A06006B445C /* SNTXPCNotifierInterface.m */; };
|
||||
@@ -132,7 +136,7 @@
|
||||
0DD0D487194F5187005F27EB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0DD0D48B194F6193005F27EB /* SNTCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */; };
|
||||
0DD0D48D194F6D5B005F27EB /* SNTCodesignCheckerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */; };
|
||||
0DD0D48F194F78F8005F27EB /* SNTBinaryInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48E194F78F8005F27EB /* SNTBinaryInfoTest.m */; };
|
||||
0DD0D48F194F78F8005F27EB /* SNTFileInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */; };
|
||||
0DD0D491194F9947005F27EB /* SNTExecutionControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */; };
|
||||
0DD0D492194F9BEF005F27EB /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
|
||||
0DD65D98184D2F0A00822DA7 /* SNTCodesignChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D59C0E317710E6000748EBF /* SNTCodesignChecker.m */; };
|
||||
@@ -141,9 +145,16 @@
|
||||
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
|
||||
0DE50F691912B0CD007B2B0C /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
|
||||
0DE50F6C19130358007B2B0C /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
|
||||
0DE50F6D191303E3007B2B0C /* SNTNotificationMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DBE65F018BEA3CC00AC994C /* SNTNotificationMessage.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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -193,18 +204,6 @@
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
0D9A7F3B1759330400035EB5 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0A84545E322F475FA0B505D5 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D0016A2192BCD3C005E7FCD /* KernelTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KernelTests; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -222,13 +221,12 @@
|
||||
0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTAboutWindowController.m; sourceTree = "<group>"; };
|
||||
0D1B476F19A53419008CADD3 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindow.xib; sourceTree = "<group>"; };
|
||||
0D260DAC18B68E12002A0B55 /* LogicTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LogicTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D260DAD18B68E12002A0B55 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||
0D260DB118B68E12002A0B55 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
|
||||
0D260DB718B68E12002A0B55 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
||||
0D260DC018B69078002A0B55 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
|
||||
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>"; };
|
||||
@@ -242,7 +240,7 @@
|
||||
0D37C10E18F6029A0069BC61 /* SNTDatabaseTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDatabaseTable.m; sourceTree = "<group>"; };
|
||||
0D385DB6180DE4A900418BC6 /* Santa.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Santa.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D385DB7180DE4A900418BC6 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
0D385DBF180DE4A900418BC6 /* Santa-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Santa-Info.plist"; sourceTree = "<group>"; };
|
||||
0D385DBF180DE4A900418BC6 /* SantaGUI-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SantaGUI-Info.plist"; sourceTree = "<group>"; };
|
||||
0D385DC3180DE4A900418BC6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
0D385DC5180DE4A900418BC6 /* Santa-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Santa-Prefix.pch"; sourceTree = "<group>"; };
|
||||
0D385DCF180DE4A900418BC6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
@@ -259,6 +257,7 @@
|
||||
0D416400191974F1006A356A /* SNTCommandSyncStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncStatus.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>"; };
|
||||
0D42D2B319D1D98A00955F08 /* SNTSystemInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTSystemInfo.h; sourceTree = "<group>"; };
|
||||
0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTSystemInfo.m; sourceTree = "<group>"; };
|
||||
0D42D2B619D2042900955F08 /* SNTConfigurator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTConfigurator.h; sourceTree = "<group>"; };
|
||||
@@ -301,19 +300,18 @@
|
||||
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>"; };
|
||||
0DBE65EF18BEA3CC00AC994C /* SNTNotificationMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTNotificationMessage.h; sourceTree = "<group>"; };
|
||||
0DBE65F018BEA3CC00AC994C /* SNTNotificationMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTNotificationMessage.m; sourceTree = "<group>"; };
|
||||
0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTRuleTable.m; sourceTree = "<group>"; };
|
||||
0DC5D86F192160180078A5C0 /* SNTCommandSyncLogUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncLogUpload.h; sourceTree = "<group>"; };
|
||||
0DC5D870192160180078A5C0 /* SNTCommandSyncLogUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncLogUpload.m; sourceTree = "<group>"; };
|
||||
0DC8C9E3180CC3BC00FCFB29 /* SNTXPCNotifierInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTXPCNotifierInterface.h; sourceTree = "<group>"; };
|
||||
0DCD5F771909C659006B445C /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; };
|
||||
0DCD5FBE1909D64A006B445C /* SNTCommandBinaryInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandBinaryInfo.m; sourceTree = "<group>"; };
|
||||
0DCD6040190ACCB8006B445C /* SNTBinaryInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTBinaryInfo.h; sourceTree = "<group>"; };
|
||||
0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTBinaryInfo.m; sourceTree = "<group>"; };
|
||||
0DCD6040190ACCB8006B445C /* SNTFileInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTFileInfo.h; sourceTree = "<group>"; };
|
||||
0DCD6041190ACCB8006B445C /* SNTFileInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileInfo.m; sourceTree = "<group>"; };
|
||||
0DCD604919105433006B445C /* SNTStoredEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTStoredEvent.h; sourceTree = "<group>"; };
|
||||
0DCD604A19105433006B445C /* SNTStoredEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTStoredEvent.m; sourceTree = "<group>"; };
|
||||
0DCD604E19115A06006B445C /* SNTXPCNotifierInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCNotifierInterface.m; sourceTree = "<group>"; };
|
||||
@@ -325,14 +323,23 @@
|
||||
0DCD6061191188B1006B445C /* SNTAuthenticatingURLSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTAuthenticatingURLSession.m; sourceTree = "<group>"; };
|
||||
0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCertificateTest.m; sourceTree = "<group>"; };
|
||||
0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCodesignCheckerTest.m; sourceTree = "<group>"; };
|
||||
0DD0D48E194F78F8005F27EB /* SNTBinaryInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTBinaryInfoTest.m; sourceTree = "<group>"; };
|
||||
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileInfoTest.m; sourceTree = "<group>"; };
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTExecutionControllerTest.m; sourceTree = "<group>"; };
|
||||
0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandFlushCache.m; sourceTree = "<group>"; };
|
||||
0DE50F6619127169007B2B0C /* SNTRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTRule.h; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LogicTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8003CA1D3E46447BCEA56440 /* Pods-santad.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.release.xcconfig"; path = "Pods/Target Support Files/Pods-santad/Pods-santad.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -355,8 +362,6 @@
|
||||
files = (
|
||||
0D3AFBF618FB4C7E0087BCEE /* Cocoa.framework in Frameworks */,
|
||||
0D3AFBF818FB4C870087BCEE /* IOKit.framework in Frameworks */,
|
||||
0D260DC118B69078002A0B55 /* Security.framework in Frameworks */,
|
||||
0D260DAE18B68E12002A0B55 /* XCTest.framework in Frameworks */,
|
||||
8BFD9B39112F4D16B3D0EFFB /* libPods-LogicTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -365,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 */,
|
||||
@@ -375,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 */,
|
||||
@@ -407,11 +414,13 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D260DB018B68E12002A0B55 /* Resources */,
|
||||
0DD0D48E194F78F8005F27EB /* SNTBinaryInfoTest.m */,
|
||||
0DD0D48A194F6193005F27EB /* SNTCertificateTest.m */,
|
||||
0DD0D48C194F6D5B005F27EB /* SNTCodesignCheckerTest.m */,
|
||||
0D10BE8A1A0AB23300C0C944 /* SNTDERDecoderTest.m */,
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
|
||||
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
|
||||
);
|
||||
path = LogicTests;
|
||||
@@ -420,12 +429,13 @@
|
||||
0D260DB018B68E12002A0B55 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D2CD4601A81C7B100C9C910 /* dn.plist */,
|
||||
0D6FDC8618C6913D0044685C /* apple.pem */,
|
||||
0D6FDC8218C68D7E0044685C /* GIAG2.crt */,
|
||||
0D6F12D919EDE411006B218E /* tubitak.crt */,
|
||||
0D6FDC8418C68E500044685C /* GIAG2.pem */,
|
||||
0D260DB118B68E12002A0B55 /* Tests-Info.plist */,
|
||||
0D260DB718B68E12002A0B55 /* Tests-Prefix.pch */,
|
||||
0D6FDC8418C68E500044685C /* GIAG2.pem */,
|
||||
0D6F12D919EDE411006B218E /* tubitak.crt */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -438,8 +448,10 @@
|
||||
0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */,
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */,
|
||||
0DE4C8A318FF3AFA00466D04 /* flushcache */,
|
||||
409232751A51914400A04527 /* rule */,
|
||||
0D827E6819DF4F3F006EC811 /* status */,
|
||||
0D35BDB618FD84FC00921A21 /* sync */,
|
||||
0DB390971AB1E0F200614002 /* version */,
|
||||
0D35BDA318FD71CE00921A21 /* Resources */,
|
||||
);
|
||||
name = santactl;
|
||||
@@ -449,8 +461,8 @@
|
||||
0D35BDA318FD71CE00921A21 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */,
|
||||
0D28E5E41926B55600280F87 /* santactl-Info.plist */,
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -458,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 */,
|
||||
@@ -503,7 +519,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D385DCF180DE4A900418BC6 /* Images.xcassets */,
|
||||
0D385DBF180DE4A900418BC6 /* Santa-Info.plist */,
|
||||
0D385DBF180DE4A900418BC6 /* SantaGUI-Info.plist */,
|
||||
0D385DC5180DE4A900418BC6 /* Santa-Prefix.pch */,
|
||||
0D1B476F19A53419008CADD3 /* AboutWindow.xib */,
|
||||
0D385DE9180DE51600418BC6 /* MessageWindow.xib */,
|
||||
@@ -568,15 +584,14 @@
|
||||
0D91BCB6174E8A7E00131A7D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DF395651AB76ABC00CBC520 /* libz.dylib */,
|
||||
0DCD5F771909C659006B445C /* SecurityInterface.framework */,
|
||||
0D3AFBF718FB4C870087BCEE /* IOKit.framework */,
|
||||
0D260DC018B69078002A0B55 /* Security.framework */,
|
||||
0D8C200B180F359A00CE2BF8 /* Security.framework */,
|
||||
0D4A5006176A4602004F63BF /* Security.framework */,
|
||||
0D91BCB8174E8A7E00131A7D /* Kernel.framework */,
|
||||
0D9A7F3E1759330500035EB5 /* Foundation.framework */,
|
||||
0D385DB7180DE4A900418BC6 /* Cocoa.framework */,
|
||||
0D260DAD18B68E12002A0B55 /* XCTest.framework */,
|
||||
752301D17AA44BDE8B6D0541 /* libPods-LogicTests.a */,
|
||||
0A84545E322F475FA0B505D5 /* libPods-santad.a */,
|
||||
);
|
||||
@@ -586,12 +601,12 @@
|
||||
0D91BCB9174E8A7E00131A7D /* santa-driver */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D4644C4182AF81700098690 /* SantaDecisionManager.h */,
|
||||
0D4644C3182AF81700098690 /* SantaDecisionManager.cc */,
|
||||
0D9A7F321759144800035EB5 /* SantaDriver.h */,
|
||||
0D9A7F311759144800035EB5 /* SantaDriver.cc */,
|
||||
0D9A7F361759148E00035EB5 /* SantaDriverClient.h */,
|
||||
0D9A7F351759148E00035EB5 /* SantaDriverClient.cc */,
|
||||
0D4644C4182AF81700098690 /* SantaDecisionManager.h */,
|
||||
0D4644C3182AF81700098690 /* SantaDecisionManager.cc */,
|
||||
0D7A7AF2174FCF4C00B77646 /* SantaMessage.h */,
|
||||
0D7A7AF1174FCF4C00B77646 /* SantaMessage.cc */,
|
||||
0DA36C1F199EA46600A129D6 /* Resources */,
|
||||
@@ -603,8 +618,6 @@
|
||||
0D91BCD5174E8AAB00131A7D /* common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DCD6040190ACCB8006B445C /* SNTBinaryInfo.h */,
|
||||
0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */,
|
||||
0D1AF475187C7A2C00D3298D /* SNTCertificate.h */,
|
||||
0D1AF476187C7A2C00D3298D /* SNTCertificate.m */,
|
||||
0D59C0E217710E6000748EBF /* SNTCodesignChecker.h */,
|
||||
@@ -614,11 +627,13 @@
|
||||
0D42D2B719D2042900955F08 /* SNTConfigurator.m */,
|
||||
0D10BE881A0AAC2100C0C944 /* SNTDropRootPrivs.h */,
|
||||
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */,
|
||||
0DCD6040190ACCB8006B445C /* SNTFileInfo.h */,
|
||||
0DCD6041190ACCB8006B445C /* SNTFileInfo.m */,
|
||||
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */,
|
||||
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */,
|
||||
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */,
|
||||
0D28E5E119269B3600280F87 /* SNTLogging.h */,
|
||||
0DA73C9E1934F8100056D7C4 /* SNTLogging.m */,
|
||||
0DBE65EF18BEA3CC00AC994C /* SNTNotificationMessage.h */,
|
||||
0DBE65F018BEA3CC00AC994C /* SNTNotificationMessage.m */,
|
||||
0DE50F6619127169007B2B0C /* SNTRule.h */,
|
||||
0DE50F671912716A007B2B0C /* SNTRule.m */,
|
||||
0DCD604919105433006B445C /* SNTStoredEvent.h */,
|
||||
@@ -678,6 +693,14 @@
|
||||
name = DataLayer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DB390971AB1E0F200614002 /* version */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DB390981AB1E11400614002 /* SNTCommandVersion.m */,
|
||||
);
|
||||
name = version;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -705,6 +728,14 @@
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
409232751A51914400A04527 /* rule */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
409232791A51B65D00A04527 /* SNTCommandRule.m */,
|
||||
);
|
||||
name = rule;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -762,6 +793,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D35BDA918FD71CE00921A21 /* Build configuration list for PBXNativeTarget "santactl" */;
|
||||
buildPhases = (
|
||||
0DD98E671A5DD02000A754C6 /* Update Version Info */,
|
||||
0D35BD9A18FD71CE00921A21 /* Sources */,
|
||||
0D35BD9B18FD71CE00921A21 /* Frameworks */,
|
||||
);
|
||||
@@ -778,6 +810,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D385DE3180DE4A900418BC6 /* Build configuration list for PBXNativeTarget "Santa" */;
|
||||
buildPhases = (
|
||||
0DD98E681A5DD03E00A754C6 /* Update Version Info */,
|
||||
0D385DB2180DE4A900418BC6 /* Sources */,
|
||||
0D385DB3180DE4A900418BC6 /* Frameworks */,
|
||||
0D385DB4180DE4A900418BC6 /* Resources */,
|
||||
@@ -795,6 +828,8 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D91BCC3174E8A7E00131A7D /* Build configuration list for PBXNativeTarget "santa-driver" */;
|
||||
buildPhases = (
|
||||
0D45F4271A5DCB7A00BF4375 /* Update Version Info */,
|
||||
0DD98E691A5DD5C900A754C6 /* Update Module Version */,
|
||||
0D91BCAE174E8A7E00131A7D /* Sources */,
|
||||
0D91BCB0174E8A7E00131A7D /* Headers */,
|
||||
);
|
||||
@@ -812,9 +847,9 @@
|
||||
buildConfigurationList = 0D9A7F471759330500035EB5 /* Build configuration list for PBXNativeTarget "santad" */;
|
||||
buildPhases = (
|
||||
34C9C9E8C5454BBE980DF8A9 /* Check Pods Manifest.lock */,
|
||||
0DD98E661A5DCED300A754C6 /* Update Version Info */,
|
||||
0D9A7F391759330400035EB5 /* Sources */,
|
||||
0D9A7F3A1759330400035EB5 /* Frameworks */,
|
||||
0D9A7F3B1759330400035EB5 /* CopyFiles */,
|
||||
3CDBFA3554E7465D93EAA5C8 /* Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -834,25 +869,9 @@
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0510;
|
||||
TargetAttributes = {
|
||||
0D0016A1192BCD3C005E7FCD = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
};
|
||||
0D260DAB18B68E12002A0B55 = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
TestTargetID = 0D385DB5180DE4A900418BC6;
|
||||
};
|
||||
0D35BD9D18FD71CE00921A21 = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
};
|
||||
0D385DB5180DE4A900418BC6 = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
};
|
||||
0D91BCB3174E8A7E00131A7D = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
};
|
||||
0D9A7F3C1759330400035EB5 = {
|
||||
DevelopmentTeam = 48U5E5R4XN;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 0D91BCAB174E8A6500131A7D /* Build configuration list for PBXProject "Santa" */;
|
||||
@@ -887,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;
|
||||
@@ -904,6 +924,22 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
0D45F4271A5DCB7A00BF4375 /* Update Version Info */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/Source/santa-driver/Resources/santa-driver-Info.plist",
|
||||
);
|
||||
name = "Update Version Info";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/santa-driver-Info.plist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nGIT_COMMIT=$(git rev-parse --short HEAD)\n\ncp ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\n\nif [ $CONFIGURATION = \"Debug\" ]; then\n newVersion=\"${GIT_TAG}d ${GIT_COMMIT}\"\nelse\n newVersion=\"${GIT_TAG}\"\nfi\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion ${GIT_TAG}\" ${SCRIPT_OUTPUT_FILE_0}\n/usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString ${newVersion}\" ${SCRIPT_OUTPUT_FILE_0}";
|
||||
};
|
||||
0D673DAD18FC9017009C5B06 /* Delete existing coverage files */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -919,6 +955,68 @@
|
||||
shellScript = "# Delete existing gcda files to prevent the build log being filled with hundreds of lines\n# of \"profiling:invalid arc tag\".\n# TODO(rah): Remove when Xcode fixes this.\nfind . -name \"*.gcda\" -print0 | xargs -0 rm";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
0DD98E661A5DCED300A754C6 /* Update Version Info */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/Source/santad/Resources/santad-Info.plist",
|
||||
);
|
||||
name = "Update Version Info";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/santad-Info.plist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nGIT_COMMIT=$(git rev-parse --short HEAD)\n\ncp ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\n\nif [ $CONFIGURATION = \"Debug\" ]; then\nnewVersion=\"${GIT_TAG}d ${GIT_COMMIT}\"\nelse\nnewVersion=\"${GIT_TAG}\"\nfi\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion ${GIT_TAG}\" ${SCRIPT_OUTPUT_FILE_0}\n/usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString ${newVersion}\" ${SCRIPT_OUTPUT_FILE_0}";
|
||||
};
|
||||
0DD98E671A5DD02000A754C6 /* Update Version Info */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/Source/santactl/Resources/santactl-Info.plist",
|
||||
);
|
||||
name = "Update Version Info";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/santactl-Info.plist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nGIT_COMMIT=$(git rev-parse --short HEAD)\n\ncp ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\n\nif [ $CONFIGURATION = \"Debug\" ]; then\nnewVersion=\"${GIT_TAG}d ${GIT_COMMIT}\"\nelse\nnewVersion=\"${GIT_TAG}\"\nfi\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion ${GIT_TAG}\" ${SCRIPT_OUTPUT_FILE_0}\n/usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString ${newVersion}\" ${SCRIPT_OUTPUT_FILE_0}";
|
||||
};
|
||||
0DD98E681A5DD03E00A754C6 /* Update Version Info */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/Source/SantaGUI/Resources/SantaGUI-Info.plist",
|
||||
);
|
||||
name = "Update Version Info";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/SantaGUI-Info.plist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nGIT_COMMIT=$(git rev-parse --short HEAD)\n\ncp ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\n\nif [ $CONFIGURATION = \"Debug\" ]; then\nnewVersion=\"${GIT_TAG}d ${GIT_COMMIT}\"\nelse\nnewVersion=\"${GIT_TAG}\"\nfi\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion ${GIT_TAG}\" ${SCRIPT_OUTPUT_FILE_0}\n/usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString ${newVersion}\" ${SCRIPT_OUTPUT_FILE_0}";
|
||||
};
|
||||
0DD98E691A5DD5C900A754C6 /* Update Module Version */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Update Module Version";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nsed -i '' \"s/TO.BE.FILLED/${GIT_TAG}/\" ${DERIVED_FILE_DIR}/santa-driver_info.c";
|
||||
};
|
||||
34C9C9E8C5454BBE980DF8A9 /* Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -994,10 +1092,10 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D88680C1AC48A1400B86659 /* SNTSystemInfo.m in Sources */,
|
||||
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
|
||||
0D6FDC8F18C7F0200044685C /* SNTNotificationMessage.m in Sources */,
|
||||
0D3AFBF018FB4C6C0087BCEE /* SNTDriverManager.m in Sources */,
|
||||
0DCD6044190ACCB8006B445C /* SNTBinaryInfo.m in Sources */,
|
||||
0DCD6044190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
0D6FDC9718C93A020044685C /* SNTXPCConnection.m in Sources */,
|
||||
0D3AFBEB18FB48E70087BCEE /* SNTDatabaseTable.m in Sources */,
|
||||
0DD0D491194F9947005F27EB /* SNTExecutionControllerTest.m in Sources */,
|
||||
@@ -1006,13 +1104,16 @@
|
||||
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 */,
|
||||
0DCD605719115E54006B445C /* SNTDaemonControlController.m in Sources */,
|
||||
0D41DAD41A7C28C800A890FE /* SNTEventTableTest.m in Sources */,
|
||||
0D3AFBEE18FB4C6C0087BCEE /* SNTApplication.m in Sources */,
|
||||
0DD0D48F194F78F8005F27EB /* SNTBinaryInfoTest.m in Sources */,
|
||||
0DD0D48F194F78F8005F27EB /* SNTFileInfoTest.m in Sources */,
|
||||
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */,
|
||||
0D31DF4718D254B3002B300D /* SNTCodesignChecker.m in Sources */,
|
||||
0DD0D492194F9BEF005F27EB /* SNTLogging.m in Sources */,
|
||||
@@ -1032,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 */,
|
||||
@@ -1039,15 +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 */,
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
|
||||
0D35BDA218FD71CE00921A21 /* main.m in Sources */,
|
||||
0DCD6043190ACCB8006B445C /* SNTBinaryInfo.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 */,
|
||||
@@ -1060,9 +1165,10 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D54E0B11976F8D3000BB59F /* SNTBinaryInfo.m in Sources */,
|
||||
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 */,
|
||||
@@ -1073,7 +1179,8 @@
|
||||
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */,
|
||||
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */,
|
||||
0DA73CA11934F8100056D7C4 /* SNTLogging.m in Sources */,
|
||||
0DE50F6D191303E3007B2B0C /* SNTNotificationMessage.m in Sources */,
|
||||
0DEFB7C51ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
|
||||
0D20710E1A7C4A86008B0A9A /* SNTStoredEvent.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1092,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 */,
|
||||
@@ -1100,7 +1208,8 @@
|
||||
0D9A7F421759330500035EB5 /* main.m in Sources */,
|
||||
0D1AF477187C7A2C00D3298D /* SNTCertificate.m in Sources */,
|
||||
0DA73C9F1934F8100056D7C4 /* SNTLogging.m in Sources */,
|
||||
0DCD6042190ACCB8006B445C /* SNTBinaryInfo.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 */,
|
||||
@@ -1108,7 +1217,6 @@
|
||||
0D377C2A17A071B7008453DB /* SNTEventTable.m in Sources */,
|
||||
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */,
|
||||
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */,
|
||||
0DBE65F118BEA3CC00AC994C /* SNTNotificationMessage.m in Sources */,
|
||||
0D59C0E417710E6000748EBF /* SNTCodesignChecker.m in Sources */,
|
||||
0D42D2B819D2042900955F08 /* SNTConfigurator.m in Sources */,
|
||||
0DCD605519115D17006B445C /* SNTXPCControlInterface.m in Sources */,
|
||||
@@ -1219,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;
|
||||
@@ -1269,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;
|
||||
@@ -1314,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;
|
||||
@@ -1340,7 +1447,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santactl/Resources/santactl-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santactl-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
@@ -1352,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;
|
||||
@@ -1372,7 +1480,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santactl/Resources/santactl-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santactl-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
@@ -1385,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;
|
||||
@@ -1411,7 +1520,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/SantaGUI/Resources/Santa-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/SantaGUI-Info.plist";
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
PROVISIONING_PROFILE = "";
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -1425,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;
|
||||
@@ -1445,7 +1555,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/SantaGUI/Resources/Santa-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/SantaGUI-Info.plist";
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
PROVISIONING_PROFILE = "";
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -1459,7 +1569,7 @@
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.9;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PROVISIONING_PROFILE = "";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
@@ -1475,7 +1585,7 @@
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.9;
|
||||
PROVISIONING_PROFILE = "";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -1487,12 +1597,12 @@
|
||||
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;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
@@ -1505,10 +1615,10 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "Source/santa-driver/Resources/santa-driver-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santa-driver-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
MODULE_NAME = "com.google.santa-driver";
|
||||
MODULE_VERSION = 0.7;
|
||||
MODULE_VERSION = TO.BE.FILLED;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -1522,12 +1632,12 @@
|
||||
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;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
@@ -1537,10 +1647,10 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "Source/santa-driver/Resources/santa-driver-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santa-driver-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
MODULE_NAME = "com.google.santa-driver";
|
||||
MODULE_VERSION = 0.7;
|
||||
MODULE_VERSION = TO.BE.FILLED;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WARNING_CFLAGS = "-Wno-deprecated-register";
|
||||
@@ -1568,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;
|
||||
@@ -1589,7 +1700,7 @@
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santad/Resources/santad-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
|
||||
INSTALL_PATH = /usr/sbin;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1602,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;
|
||||
@@ -1616,7 +1728,7 @@
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santad/Resources/santad-Info.plist";
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
|
||||
INSTALL_PATH = /usr/sbin;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
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>
|
||||
@@ -42,6 +42,7 @@
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
debugAsWhichUser = "root"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
|
||||
@@ -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,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="14B25" 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="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>
|
||||
@@ -14,18 +15,14 @@
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="none" id="9Bq-yh-54f" customClass="SNTMessageWindow">
|
||||
<windowStyleMask key="styleMask" utility="YES"/>
|
||||
<rect key="contentRect" x="167" y="107" width="550" height="275"/>
|
||||
<rect key="contentRect" x="167" y="107" width="550" height="331"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
|
||||
<view key="contentView" id="Iwq-Lx-rLv">
|
||||
<rect key="frame" x="0.0" y="0.0" width="550" height="275"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="550" height="331"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="t8c-Fx-e5h">
|
||||
<rect key="frame" x="234" y="210" width="83" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="KoG-v6-GfK"/>
|
||||
<constraint firstAttribute="width" constant="79" id="oS3-CE-1vv"/>
|
||||
</constraints>
|
||||
<rect key="frame" x="234" y="261" width="83" height="40"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Santa" id="7YA-iB-Zma">
|
||||
<font key="font" size="34" name="HelveticaNeue-UltraLight"/>
|
||||
<color key="textColor" red="0.18696189413265307" green="0.18696189413265307" blue="0.18696189413265307" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -33,9 +30,9 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cD5-Su-lXR">
|
||||
<rect key="frame" x="23" y="168" width="504" height="17"/>
|
||||
<rect key="frame" x="25" y="214" width="500" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="500" id="q9O-xW-hnS"/>
|
||||
<constraint firstAttribute="width" constant="496" id="XgJ-EV-tBa"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="center" title="A message to the user goes here..." allowsEditingTextAttributes="YES" id="5tH-bG-UJA">
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -43,36 +40,13 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.attributedCustomMessage" id="NH1-gV-Cor">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">The following application has been blocked from executing because its trustworthiness cannot be determined.</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="-2" name="value" keyPath="self.attributedCustomMessage" id="376-sj-4Q1"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="1000" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="GYD-v8-fqH">
|
||||
<rect key="frame" x="31" y="91" width="32" height="32"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSBonjour" id="jKM-qY-7mp"/>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.bundleIcon" id="X4L-aD-P21">
|
||||
<dictionary key="options">
|
||||
<bool key="NSConditionallySetsEnabled" value="NO"/>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d9e-Wv-Y5H">
|
||||
<rect key="frame" x="111" y="126" width="34" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Path" id="KgY-X1-ESG">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="pc8-G9-4pJ">
|
||||
<rect key="frame" x="154" y="126" width="350" height="17"/>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pc8-G9-4pJ">
|
||||
<rect key="frame" x="175" y="167" width="324" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="346" id="BYY-2q-Lmb"/>
|
||||
<constraint firstAttribute="width" constant="320" id="xVR-j3-dLw"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" selectable="YES" sendsActionOnEndEditing="YES" alignment="left" title="Binary Path" id="E7T-9h-ofr">
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -80,49 +54,109 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.event.path" id="4Nh-Ue-aCb"/>
|
||||
<binding destination="-2" name="value" keyPath="self.event.filePath" id="qfp-sR-Nmu"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KEB-eH-x2Y">
|
||||
<rect key="frame" x="96" y="99" width="46" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="SHA-1" id="eKN-Ic-5zy">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="PXc-xv-A28">
|
||||
<rect key="frame" x="155" y="99" width="88" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" title="Binary SHA-1" id="X4W-9e-eIu">
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PXc-xv-A28">
|
||||
<rect key="frame" x="175" y="117" width="304" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="300" id="4hh-R2-86s"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="charWrapping" selectable="YES" sendsActionOnEndEditing="YES" title="File SHA-256" id="X4W-9e-eIu">
|
||||
<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"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.event.SHA1" id="KuE-WW-9av"/>
|
||||
<binding destination="-2" name="value" keyPath="self.event.fileSHA256" id="SzX-Ep-rBa"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" verticalCompressionResistancePriority="499" translatesAutoresizingMaskIntoConstraints="NO" id="lvJ-Rk-UT5">
|
||||
<rect key="frame" x="78" y="72" width="66" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Publisher" id="yL9-yD-JXX">
|
||||
<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="305" id="Dem-wH-KHm"/>
|
||||
</constraints>
|
||||
<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"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.publisherInfo" id="CEI-Cu-7pC">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">Not code-signed</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oFj-ol-xpL">
|
||||
<rect key="frame" x="18" y="92" width="120" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="User" id="1ut-uT-hQD">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button toolTip="Show code signing certificate chain" translatesAutoresizingMaskIntoConstraints="NO" id="cJf-k6-OxS">
|
||||
<rect key="frame" x="322" y="75" width="10" height="10"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lvJ-Rk-UT5">
|
||||
<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"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d9e-Wv-Y5H">
|
||||
<rect key="frame" x="18" y="167" width="120" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="10" id="c3b-iv-bWa"/>
|
||||
<constraint firstAttribute="width" constant="10" id="fXl-na-Lwx"/>
|
||||
<constraint firstAttribute="width" constant="116" id="Kqd-nX-7df"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="NSFollowLinkFreestandingTemplate" imagePosition="overlaps" alignment="center" refusesFirstResponder="YES" imageScaling="proportionallyDown" inset="2" id="R72-Qy-Xbb">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Path" id="KgY-X1-ESG">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KEB-eH-x2Y">
|
||||
<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"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="h6f-PY-cc0">
|
||||
<rect key="frame" x="175" y="92" width="368" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="364" id="on6-pj-m2k"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Executing User" id="HRT-Be-ePf">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" white="0.0" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.event.executingUser" id="xe2-U2-WrZ"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="4Li-ul-zIi">
|
||||
<rect key="frame" x="154" y="92" width="5" height="92"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<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.binaryCert" id="xpJ-jl-aUN">
|
||||
<binding destination="-2" name="hidden" keyPath="self.publisherInfo" id="fFR-f3-Oiw">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSIsNil</string>
|
||||
</dictionary>
|
||||
@@ -130,12 +164,12 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BbV-3h-mmL">
|
||||
<rect key="frame" x="220" y="23" width="110" height="25"/>
|
||||
<rect key="frame" x="282" y="33" width="110" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="110" id="HdL-6x-X4f"/>
|
||||
<constraint firstAttribute="height" constant="22" id="YYm-GI-ojT"/>
|
||||
<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">
|
||||
<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">
|
||||
@@ -147,56 +181,68 @@ DQ
|
||||
<action selector="closeWindow:" target="-2" id="qQq-gh-8lw"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="C3G-wL-u7w">
|
||||
<rect key="frame" x="154" y="72" width="159" height="17"/>
|
||||
<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="height" constant="17" id="re0-7U-qcL"/>
|
||||
<constraint firstAttribute="width" priority="900" constant="112" id="Pec-Pa-4aZ"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Code signing information" placeholderString="" id="ztA-La-XgT">
|
||||
<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"/>
|
||||
<color key="textColor" white="0.0" alpha="0.5" colorSpace="deviceWhite"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.binaryCert" id="eFt-oy-SXL">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">Not code-signed</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<action selector="openEventDetails:" target="-2" id="VhL-ql-rCV"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="d9e-Wv-Y5H" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="113" id="3oY-g4-wHW"/>
|
||||
<constraint firstItem="BbV-3h-mmL" firstAttribute="top" secondItem="PXc-xv-A28" secondAttribute="bottom" priority="800" constant="52" id="42Z-62-hKo"/>
|
||||
<constraint firstItem="cD5-Su-lXR" firstAttribute="top" secondItem="t8c-Fx-e5h" secondAttribute="bottom" constant="25" id="4Hn-vu-fva"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="top" secondItem="PXc-xv-A28" secondAttribute="bottom" constant="10" id="7Pr-bA-HgG"/>
|
||||
<constraint firstItem="PXc-xv-A28" firstAttribute="top" secondItem="pc8-G9-4pJ" secondAttribute="bottom" constant="10" id="8LX-e8-bKv"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="top" secondItem="d9e-Wv-Y5H" secondAttribute="top" id="94E-d6-Jrg"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="leading" secondItem="d9e-Wv-Y5H" secondAttribute="trailing" constant="13" id="A6N-gA-dt5"/>
|
||||
<constraint firstItem="KEB-eH-x2Y" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="98" id="CYj-Gm-XZp"/>
|
||||
<constraint firstItem="PXc-xv-A28" firstAttribute="leading" secondItem="KEB-eH-x2Y" secondAttribute="trailing" constant="17" id="IGi-bx-nBP"/>
|
||||
<constraint firstItem="lvJ-Rk-UT5" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="80" id="O3p-RO-0ZJ"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="centerY" secondItem="cJf-k6-OxS" secondAttribute="centerY" constant="-1" id="R0U-iV-5Fx"/>
|
||||
<constraint firstAttribute="centerX" secondItem="t8c-Fx-e5h" secondAttribute="centerX" id="SHu-BF-01V"/>
|
||||
<constraint firstAttribute="centerX" secondItem="BbV-3h-mmL" secondAttribute="centerX" id="UAx-Xk-9DE"/>
|
||||
<constraint firstItem="KEB-eH-x2Y" firstAttribute="top" secondItem="PXc-xv-A28" secondAttribute="top" id="YiW-o8-HZ2"/>
|
||||
<constraint firstItem="BbV-3h-mmL" firstAttribute="top" secondItem="C3G-wL-u7w" secondAttribute="bottom" constant="25" id="Zxm-Pa-Ryj"/>
|
||||
<constraint firstItem="lvJ-Rk-UT5" firstAttribute="top" secondItem="C3G-wL-u7w" secondAttribute="top" id="adm-oT-FAf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="BbV-3h-mmL" secondAttribute="bottom" constant="25" id="awW-Dh-Xl4"/>
|
||||
<constraint firstItem="GYD-v8-fqH" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="31" id="btT-jY-NXw"/>
|
||||
<constraint firstItem="GYD-v8-fqH" firstAttribute="centerY" secondItem="KEB-eH-x2Y" secondAttribute="centerY" id="cOS-EE-Mw8"/>
|
||||
<constraint firstItem="C3G-wL-u7w" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="trailing" constant="14" id="ewf-Pg-nRK"/>
|
||||
<constraint firstAttribute="centerX" secondItem="cD5-Su-lXR" secondAttribute="centerX" id="goV-ub-zwi"/>
|
||||
<constraint firstItem="t8c-Fx-e5h" firstAttribute="top" secondItem="Iwq-Lx-rLv" secondAttribute="top" constant="25" id="mY6-FP-uEK"/>
|
||||
<constraint firstItem="pc8-G9-4pJ" firstAttribute="top" secondItem="cD5-Su-lXR" secondAttribute="bottom" constant="25" id="pfg-1u-Yfj"/>
|
||||
<constraint firstItem="cJf-k6-OxS" firstAttribute="leading" secondItem="C3G-wL-u7w" secondAttribute="trailing" constant="11" id="sMW-KK-A28"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="bottom" secondItem="4Li-ul-zIi" secondAttribute="bottom" id="1Nc-gl-xMe"/>
|
||||
<constraint firstItem="BbV-3h-mmL" firstAttribute="top" secondItem="oFj-ol-xpL" secondAttribute="bottom" constant="35" id="7K6-bY-Rn6"/>
|
||||
<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="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" 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="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="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="113" y="777.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSBonjour" width="32" height="32"/>
|
||||
<image name="NSFollowLinkFreestandingTemplate" width="14" height="14"/>
|
||||
<image name="NSInfo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -2,30 +2,26 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.${PRODUCT_NAME:rfc1034identifier}GUI</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.7</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Google, Inc.</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.${PRODUCT_NAME:rfc1034identifier}GUI</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.7</string>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Google, Inc.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,4 +14,8 @@
|
||||
|
||||
@interface SNTAboutWindowController : NSWindowController
|
||||
|
||||
@property IBOutlet NSButton *moreInfoButton;
|
||||
|
||||
- (IBAction)openMoreInfoURL:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,6 +12,8 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
///
|
||||
/// Initiates and manages the connection to santad
|
||||
///
|
||||
@interface SNTAppDelegate : NSObject<NSApplicationDelegate>
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -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,8 +33,25 @@
|
||||
|
||||
- (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];
|
||||
|
||||
NSNotificationCenter *workspaceNotifications = [[NSWorkspace sharedWorkspace] notificationCenter];
|
||||
[workspaceNotifications addObserver:self
|
||||
selector:@selector(killConnection)
|
||||
name:NSWorkspaceSessionDidResignActiveNotification
|
||||
object:nil];
|
||||
[workspaceNotifications addObserver:self
|
||||
selector:@selector(createConnection)
|
||||
name:NSWorkspaceSessionDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
[self createConnection];
|
||||
}
|
||||
|
||||
@@ -45,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 = ^{
|
||||
@@ -58,10 +77,18 @@
|
||||
[self.listener resume];
|
||||
}
|
||||
|
||||
- (void)killConnection {
|
||||
self.listener.invalidationHandler = nil;
|
||||
[self.listener invalidate];
|
||||
self.listener = nil;
|
||||
}
|
||||
|
||||
- (void)attemptReconnection {
|
||||
// TODO(rah): Make this smarter.
|
||||
sleep(10);
|
||||
[self createConnection];
|
||||
[self performSelectorOnMainThread:@selector(createConnection)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
#pragma mark Menu Management
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,13 +12,19 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// An NSPanel that can become key/main and can fade in/out.
|
||||
///
|
||||
/// An NSPanel that can become key/main and can fade in/out.
|
||||
///
|
||||
@interface SNTMessageWindow : NSPanel
|
||||
|
||||
/// Fade the window in
|
||||
///
|
||||
/// Fade the window in
|
||||
///
|
||||
- (IBAction)fadeIn:(id)sender;
|
||||
|
||||
/// Fade the window out
|
||||
///
|
||||
/// Fade the window out
|
||||
///
|
||||
- (IBAction)fadeOut:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,34 +12,52 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTNotificationMessage;
|
||||
@class SNTStoredEvent;
|
||||
|
||||
@protocol SNTMessageWindowControllerDelegate
|
||||
- (void)windowDidClose;
|
||||
@end
|
||||
|
||||
/// Controller for a single message window.
|
||||
///
|
||||
/// Controller for a single message window.
|
||||
///
|
||||
@interface SNTMessageWindowController : NSWindowController
|
||||
|
||||
- (instancetype)initWithEvent:(SNTNotificationMessage *)event;
|
||||
- (instancetype)initWithEvent:(SNTStoredEvent *)event andMessage:(NSString *)message;
|
||||
|
||||
- (IBAction)showWindow:(id)sender;
|
||||
- (IBAction)closeWindow:(id)sender;
|
||||
- (IBAction)showCertInfo:(id)sender;
|
||||
|
||||
/// The execution event that this window is for
|
||||
@property SNTNotificationMessage *event;
|
||||
///
|
||||
/// The execution event that this window is for
|
||||
///
|
||||
@property SNTStoredEvent *event;
|
||||
|
||||
/// The delegate to inform when the notification is dismissed
|
||||
///
|
||||
/// The custom message to display for this event
|
||||
///
|
||||
@property NSString *customMessage;
|
||||
|
||||
///
|
||||
/// The delegate to inform when the notification is dismissed
|
||||
///
|
||||
@property(weak) id<SNTMessageWindowControllerDelegate> delegate;
|
||||
|
||||
/// A 'friendly' string representing the certificate information
|
||||
@property(readonly) IBOutlet NSString *binaryCert;
|
||||
///
|
||||
/// A 'friendly' string representing the certificate information
|
||||
///
|
||||
@property(readonly) NSString *publisherInfo;
|
||||
|
||||
/// An optional message to display with this block.
|
||||
@property(readonly) IBOutlet NSAttributedString *attributedCustomMessage;
|
||||
///
|
||||
/// An optional message to display with this block.
|
||||
///
|
||||
@property(readonly) NSAttributedString *attributedCustomMessage;
|
||||
|
||||
/// If the binary is part of a bundle, this is the icon for that bundle
|
||||
@property(readonly) IBOutlet NSImage *bundleIcon;
|
||||
///
|
||||
/// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,24 +16,39 @@
|
||||
|
||||
#import <SecurityInterface/SFCertificatePanel.h>
|
||||
|
||||
#import "SNTBinaryInfo.h"
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTMessageWindow.h"
|
||||
#import "SNTNotificationMessage.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@implementation SNTMessageWindowController
|
||||
|
||||
- (instancetype)initWithEvent:(SNTNotificationMessage *)event {
|
||||
- (instancetype)initWithEvent:(SNTStoredEvent *)event andMessage:(NSString *)message {
|
||||
self = [super initWithWindowNibName:@"MessageWindow"];
|
||||
if (self) {
|
||||
_event = event;
|
||||
[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];
|
||||
[self.window center];
|
||||
|
||||
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];
|
||||
}
|
||||
@@ -48,8 +63,8 @@
|
||||
|
||||
- (IBAction)showCertInfo:(id)sender {
|
||||
// SFCertificatePanel expects an NSArray of SecCertificateRef's
|
||||
NSMutableArray *certArray = [NSMutableArray arrayWithCapacity:[self.event.certificates count]];
|
||||
for (SNTCertificate *cert in self.event.certificates) {
|
||||
NSMutableArray *certArray = [NSMutableArray arrayWithCapacity:[self.event.signingChain count]];
|
||||
for (SNTCertificate *cert in self.event.signingChain) {
|
||||
[certArray addObject:(id)cert.certRef];
|
||||
}
|
||||
|
||||
@@ -61,21 +76,36 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)binaryCert {
|
||||
SNTCertificate *leafCert = self.event.leafCertificate;
|
||||
- (NSString *)publisherInfo {
|
||||
SNTCertificate *leafCert = [self.event.signingChain firstObject];
|
||||
|
||||
if (leafCert.commonName && leafCert.orgName) {
|
||||
return [NSString stringWithFormat:@"%@ - %@", leafCert.commonName, leafCert.orgName];
|
||||
return [NSString stringWithFormat:@"%@ - %@", leafCert.orgName, leafCert.commonName];
|
||||
} else if (leafCert.commonName) {
|
||||
return leafCert.commonName;
|
||||
} else if (leafCert.orgName) {
|
||||
@@ -86,33 +116,30 @@
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedCustomMessage {
|
||||
if (self.event.customMessage) {
|
||||
NSString *htmlHeader = @"<html><head><style>"
|
||||
@"body {"
|
||||
@" font-family: 'Lucida Grande', 'Helvetica', sans-serif;"
|
||||
@" font-size: 13px;"
|
||||
@" color: #666;"
|
||||
@" text-align: center;"
|
||||
@"}"
|
||||
@"</style></head><body>";
|
||||
NSString *htmlFooter = @"</body></html>";
|
||||
NSString *fullHtml = [NSString stringWithFormat:@"%@%@%@", htmlHeader,
|
||||
self.event.customMessage, htmlFooter];
|
||||
NSData *htmlData = [fullHtml dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSAttributedString *returnStr = [[NSAttributedString alloc] initWithHTML:htmlData
|
||||
documentAttributes:NULL];
|
||||
return returnStr;
|
||||
NSString *htmlHeader = @"<html><head><style>"
|
||||
@"body {"
|
||||
@" font-family: 'Lucida Grande', 'Helvetica', sans-serif;"
|
||||
@" font-size: 13px;"
|
||||
@" color: #AAA;"
|
||||
@" text-align: center;"
|
||||
@"}"
|
||||
@"</style></head><body>";
|
||||
NSString *htmlFooter = @"</body></html>";
|
||||
|
||||
NSString *message;
|
||||
if (self.customMessage && ![self.customMessage isEqual:@""]) {
|
||||
message = self.customMessage;
|
||||
} else {
|
||||
return nil;
|
||||
message = @"The following application has been blocked from executing<br />"
|
||||
@"because its trustworthiness cannot be determined.";
|
||||
}
|
||||
}
|
||||
|
||||
- (NSImage *)bundleIcon {
|
||||
SNTBinaryInfo *bi = [[SNTBinaryInfo alloc] initWithPath:self.event.path];
|
||||
NSString *fullHTML = [NSString stringWithFormat:@"%@%@%@", htmlHeader, message, htmlFooter];
|
||||
|
||||
if (!bi || !bi.bundle) return nil;
|
||||
|
||||
return [[NSWorkspace sharedWorkspace] iconForFile:bi.bundlePath];
|
||||
NSData *htmlData = [fullHTML dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSAttributedString *returnStr = [[NSAttributedString alloc] initWithHTML:htmlData
|
||||
documentAttributes:NULL];
|
||||
return returnStr;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -15,7 +15,9 @@
|
||||
#import "SNTMessageWindowController.h"
|
||||
#import "SNTXPCNotifierInterface.h"
|
||||
|
||||
/// Keeps track of pending notifications and ensures only one is presented to the user at a time.
|
||||
///
|
||||
/// Keeps track of pending notifications and ensures only one is presented to the user at a time.
|
||||
///
|
||||
@interface SNTNotificationManager : NSObject<SNTMessageWindowControllerDelegate, SNTNotifierXPC>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,13 +14,17 @@
|
||||
|
||||
#import "SNTNotificationManager.h"
|
||||
|
||||
#import "SNTNotificationMessage.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@interface SNTNotificationManager ()
|
||||
/// The currently displayed notification
|
||||
///
|
||||
/// The currently displayed notification
|
||||
///
|
||||
@property SNTMessageWindowController *currentWindowController;
|
||||
|
||||
/// The queue of pending notifications
|
||||
///
|
||||
/// The queue of pending notifications
|
||||
///
|
||||
@property(readonly) NSMutableArray *pendingNotifications;
|
||||
@end
|
||||
|
||||
@@ -48,21 +52,32 @@
|
||||
|
||||
#pragma mark SNTNotifierXPC protocol methods
|
||||
|
||||
- (void)postBlockNotification:(SNTNotificationMessage *)event {
|
||||
- (void)postBlockNotification:(SNTStoredEvent *)event withCustomMessage:(NSString *)message {
|
||||
// See if this binary is already in the list of pending notifications.
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"event.SHA1==%@", event.SHA1];
|
||||
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:)
|
||||
withObject:event
|
||||
withObject:@{ @"event": event, @"custommsg": message }
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void)postBlockNotificationMainThread:(SNTNotificationMessage *)event {
|
||||
- (void)postBlockNotificationMainThread:(NSDictionary *)dict {
|
||||
SNTStoredEvent *event = dict[@"event"];
|
||||
NSString *msg = dict[@"custommsg"];
|
||||
|
||||
// Create message window
|
||||
SNTMessageWindowController *pendingMsg = [[SNTMessageWindowController alloc] initWithEvent:event];
|
||||
SNTMessageWindowController *pendingMsg = [[SNTMessageWindowController alloc] initWithEvent:event
|
||||
andMessage:msg];
|
||||
pendingMsg.delegate = self;
|
||||
[self.pendingNotifications addObject:pendingMsg];
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/// Copyright 2014 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.
|
||||
|
||||
/// SNTBinaryInfo represents a binary on disk, providing access to details about that binary such as
|
||||
/// the SHA-1, the Info.plist and the Mach-O data.
|
||||
@interface SNTBinaryInfo : NSObject
|
||||
|
||||
/// Designated initializer
|
||||
- (instancetype)initWithPath:(NSString *)path;
|
||||
|
||||
/// Return SHA-1 hash of this binary
|
||||
- (NSString *)SHA1;
|
||||
|
||||
/// Returns the type of Mach-O file:
|
||||
/// Dynamic Library, Kernel Extension, Fat Binary, Thin Binary
|
||||
- (NSString *)machoType;
|
||||
|
||||
/// Returns the architectures included in this binary (e.g. x86_64, ppc)
|
||||
- (NSArray *)architectures;
|
||||
|
||||
/// Returns YES if this file is a Mach-O file
|
||||
- (BOOL)isMachO;
|
||||
|
||||
/// Returns YES if this file contains multiple architectures
|
||||
- (BOOL)isFat;
|
||||
|
||||
/// Returns YES if this file is an executable Mach-O file
|
||||
- (BOOL)isExecutable;
|
||||
|
||||
/// Returns YES if this file is a dynamic library
|
||||
- (BOOL)isDylib;
|
||||
|
||||
/// Returns YES if this file is a kernel extension
|
||||
- (BOOL)isKext;
|
||||
|
||||
/// Returns YES if this file is a script (e.g. it begins #!)
|
||||
- (BOOL)isScript;
|
||||
|
||||
/// Returns an NSBundle if this file is part of a bundle.
|
||||
- (NSBundle *)bundle;
|
||||
|
||||
/// Returns the path to the bundle this file is a part of, if any.
|
||||
- (NSString *)bundlePath;
|
||||
|
||||
/// Returns either the Info.plist in the bundle this file is part of, or an embedded plist if there
|
||||
/// is one. In the odd case that a file has both an embedded Info.plist and is part of a bundle,
|
||||
/// the Info.plist from the bundle will be returned.
|
||||
- (NSDictionary *)infoPlist;
|
||||
|
||||
/// Returns the CFBundleIdentifier from this file's Info.plist
|
||||
- (NSString *)bundleIdentifier;
|
||||
|
||||
/// Returns the CFBundleName from this file's Info.plist
|
||||
- (NSString *)bundleName;
|
||||
|
||||
/// Returns the CFBundleVersion from this file's Info.plist
|
||||
- (NSString *)bundleVersion;
|
||||
|
||||
/// Returns the CFBundleShortVersionString from this file's Info.plist
|
||||
- (NSString *)bundleShortVersionString;
|
||||
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,56 +12,100 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// SNTCertificate wraps a @c SecCertificateRef to provide Objective-C accessors to
|
||||
/// commonly used certificate data. Accessors cache data for repeated access.
|
||||
///
|
||||
/// SNTCertificate wraps a @c SecCertificateRef to provide Objective-C accessors to
|
||||
/// commonly used certificate data. Accessors cache data for repeated access.
|
||||
///
|
||||
@interface SNTCertificate : NSObject<NSSecureCoding>
|
||||
|
||||
/// Initialize a SNTCertificate object with a valid SecCertificateRef. Designated initializer.
|
||||
///
|
||||
/// Initialize a SNTCertificate object with a valid SecCertificateRef. Designated initializer.
|
||||
///
|
||||
/// @param certRef valid SecCertificateRef, which will be retained.
|
||||
///
|
||||
- (instancetype)initWithSecCertificateRef:(SecCertificateRef)certRef;
|
||||
|
||||
/// Initialize a SNTCertificate object with certificate data in DER format.
|
||||
/// Returns nil if |certData| is invalid.
|
||||
///
|
||||
/// Initialize a SNTCertificate object with certificate data in DER format.
|
||||
///
|
||||
/// @param certData DER-encoded certificate data.
|
||||
/// @return initialized SNTCertificate or nil if certData is not a DER-encoded certificate.
|
||||
///
|
||||
- (instancetype)initWithCertificateDataDER:(NSData *)certData;
|
||||
|
||||
/// Initialize a SNTCertificate object with certificate data in PEM format.
|
||||
/// If multiple PEM certificates exist within the string, the first is used.
|
||||
/// Returns nil if |certData| is invalid.
|
||||
///
|
||||
/// Initialize a SNTCertificate object with certificate data in PEM format.
|
||||
/// If multiple PEM certificates exist within the string, the first is used.
|
||||
///
|
||||
/// @param certData PEM-encoded certificate data.
|
||||
/// @return initialized SNTCertifcate or nil if certData is not a PEM-encoded certificate.
|
||||
///
|
||||
- (instancetype)initWithCertificateDataPEM:(NSString *)certData;
|
||||
|
||||
/// Returns an array of SNTCertificate's for all of the certificates in |pemData|.
|
||||
///
|
||||
/// Returns an array of SNTCertificate's for all of the certificates in @c pemData.
|
||||
///
|
||||
/// @param pemData PEM-encoded certificates.
|
||||
/// @return array of SNTCertificate objects.
|
||||
///
|
||||
+ (NSArray *)certificatesFromPEM:(NSString *)pemData;
|
||||
|
||||
/// Access the underlying certificate ref.
|
||||
///
|
||||
/// Access the underlying certificate ref.
|
||||
///
|
||||
@property(readonly) SecCertificateRef certRef;
|
||||
|
||||
/// SHA-1 hash of the certificate data.
|
||||
///
|
||||
/// SHA-1 hash of the certificate data.
|
||||
///
|
||||
@property(readonly) NSString *SHA1;
|
||||
|
||||
/// Certificate data.
|
||||
///
|
||||
/// SHA-256 hash of the certificate data.
|
||||
///
|
||||
@property(readonly) NSString *SHA256;
|
||||
|
||||
///
|
||||
/// Certificate data.
|
||||
///
|
||||
@property(readonly) NSData *certData;
|
||||
|
||||
/// Common Name e.g: "Software Signing"
|
||||
///
|
||||
/// Common Name e.g: "Software Signing"
|
||||
///
|
||||
@property(readonly) NSString *commonName;
|
||||
|
||||
/// Country Name e.g: "US"
|
||||
///
|
||||
/// Country Name e.g: "US"
|
||||
///
|
||||
@property(readonly) NSString *countryName;
|
||||
|
||||
/// Organizational Name e.g: "Apple Inc."
|
||||
///
|
||||
/// Organizational Name e.g: "Apple Inc."
|
||||
///
|
||||
@property(readonly) NSString *orgName;
|
||||
|
||||
/// Organizational Unit Name e.g: "Apple Software"
|
||||
///
|
||||
/// Organizational Unit Name e.g: "Apple Software"
|
||||
///
|
||||
@property(readonly) NSString *orgUnit;
|
||||
|
||||
/// Issuer details, same fields as above.
|
||||
///
|
||||
/// Issuer details, same fields as above.
|
||||
///
|
||||
@property(readonly) NSString *issuerCommonName;
|
||||
@property(readonly) NSString *issuerCountryName;
|
||||
@property(readonly) NSString *issuerOrgName;
|
||||
@property(readonly) NSString *issuerOrgUnit;
|
||||
|
||||
/// Validity Not Before
|
||||
///
|
||||
/// Validity Not Before
|
||||
///
|
||||
@property(readonly) NSDate *validFrom;
|
||||
|
||||
/// Validity Not After
|
||||
///
|
||||
/// Validity Not After
|
||||
///
|
||||
@property(readonly) NSDate *validUntil;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -18,7 +18,7 @@
|
||||
#import <Security/Security.h>
|
||||
|
||||
@interface SNTCertificate ()
|
||||
/// A container for cached property values
|
||||
/// A container for cached property values
|
||||
@property NSMutableDictionary *memoizedData;
|
||||
@end
|
||||
|
||||
@@ -42,9 +42,10 @@ static NSString *const kCertDataKey = @"certData";
|
||||
|
||||
if (cert) {
|
||||
// Despite the header file claiming that SecCertificateCreateWithData will return NULL if
|
||||
// |certData| doesn't contain a valid DER-encoded X509 cert, this isn't always true.
|
||||
// @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];
|
||||
@@ -164,9 +165,11 @@ static NSString *const kCertDataKey = @"certData";
|
||||
|
||||
#pragma mark Private Accessors
|
||||
|
||||
///
|
||||
/// For a given selector, caches the value that selector would return on subsequent invocations,
|
||||
/// using the provided block to get the value on the first invocation.
|
||||
/// Assumes the selector's value will never change.
|
||||
///
|
||||
- (id)memoizedSelector:(SEL)selector forBlock:(id (^)(void))block {
|
||||
NSString *selName = NSStringFromSelector(selector);
|
||||
|
||||
@@ -205,10 +208,13 @@ static NSString *const kCertDataKey = @"certData";
|
||||
}];
|
||||
}
|
||||
|
||||
/// Retrieve the value with the specified label from the X509 dictionary provided
|
||||
/// @param desiredLabel The label you want, e.g: kSecOIDOrganizationName.
|
||||
/// @param dict The dictionary to look in (Subject or Issuer)
|
||||
/// @returns An @c NSString, the value for the specified label.
|
||||
///
|
||||
/// Retrieve the value with the specified label from the X509 dictionary provided
|
||||
///
|
||||
/// @param desiredLabel The label you want, e.g: kSecOIDOrganizationName.
|
||||
/// @param dict The dictionary to look in (Subject or Issuer)
|
||||
/// @return An @c NSString, the value for the specified label.
|
||||
///
|
||||
- (NSString *)x509ValueForLabel:(NSString *)desiredLabel fromDictionary:(NSDictionary *)dict {
|
||||
@try {
|
||||
NSArray *valArray = dict[(__bridge NSString *)kSecPropertyKeyValue];
|
||||
@@ -226,10 +232,13 @@ static NSString *const kCertDataKey = @"certData";
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Retrieve the specified date from the certificate's values and convert from a reference date
|
||||
/// to an NSDate object.
|
||||
///
|
||||
/// @param key The identifier for the date: @c kSecOIDX509V1ValiditityNot{Before,After}
|
||||
/// @return An @c NSDate representing the date and time the certificate is valid from or expires.
|
||||
///
|
||||
- (NSDate *)dateForX509Key:(NSString *)key {
|
||||
NSDictionary *curCertVal = [self allCertificateValues][key];
|
||||
NSNumber *value = curCertVal[(__bridge NSString *)kSecPropertyKeyValue];
|
||||
@@ -250,12 +259,29 @@ static NSString *const kCertDataKey = @"certData";
|
||||
|
||||
CC_SHA1([self.certData bytes], (CC_LONG)[self.certData length], [SHA1Buffer mutableBytes]);
|
||||
|
||||
const unsigned char *bytes = (const unsigned char *)[SHA1Buffer bytes];
|
||||
return [NSString stringWithFormat:
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
|
||||
bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16],
|
||||
bytes[17], bytes[18], bytes[19]];
|
||||
const unsigned char *bytes = (const unsigned char *)[SHA1Buffer bytes];
|
||||
NSMutableString *hexDigest = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
|
||||
[hexDigest appendFormat:@"%02x", bytes[i]];
|
||||
}
|
||||
|
||||
return hexDigest;
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)SHA256 {
|
||||
return [self memoizedSelector:_cmd forBlock:^id{
|
||||
NSMutableData *SHA256Buffer = [[NSMutableData alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH];
|
||||
|
||||
CC_SHA256([self.certData bytes], (CC_LONG)[self.certData length], [SHA256Buffer mutableBytes]);
|
||||
|
||||
const unsigned char *bytes = (const unsigned char *)[SHA256Buffer bytes];
|
||||
NSMutableString *hexDigest = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
[hexDigest appendFormat:@"%02x", bytes[i]];
|
||||
}
|
||||
|
||||
return hexDigest;
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,42 +14,77 @@
|
||||
|
||||
@class SNTCertificate;
|
||||
|
||||
/// SNTCodesignChecker validates a binary (either on-disk or in memory) has been signed
|
||||
/// and if so allows for pulling out the certificates that were used to sign it.
|
||||
///
|
||||
/// SNTCodesignChecker validates a binary (either on-disk or in memory) has been signed
|
||||
/// and if so allows for pulling out the certificates that were used to sign it.
|
||||
///
|
||||
@interface SNTCodesignChecker : NSObject
|
||||
|
||||
/// The SecStaticCodeRef that this SNTCodesignChecker is working around
|
||||
///
|
||||
/// The SecStaticCodeRef that this SNTCodesignChecker is working around
|
||||
///
|
||||
@property(readonly) SecStaticCodeRef codeRef;
|
||||
|
||||
/// Returns a dictionary of raw signing information
|
||||
///
|
||||
/// Returns a dictionary of raw signing information
|
||||
///
|
||||
@property(readonly) NSDictionary *signingInformation;
|
||||
|
||||
/// Returns an array of @c SNTCertificate objects representing the chain that signed this binary.
|
||||
///
|
||||
/// Returns an array of @c SNTCertificate objects representing the chain that signed this binary.
|
||||
///
|
||||
@property(readonly) NSArray *certificates;
|
||||
|
||||
/// Returns the leaf certificate that this binary was signed with
|
||||
///
|
||||
/// Returns the leaf certificate that this binary was signed with
|
||||
///
|
||||
@property(readonly) SNTCertificate *leafCertificate;
|
||||
|
||||
/// Returns the on-disk path of this binary.
|
||||
///
|
||||
/// Returns the on-disk path of this binary.
|
||||
///
|
||||
@property(readonly) NSString *binaryPath;
|
||||
|
||||
/// Initialize an @c SNTCodesignChecker with a SecStaticCodeRef
|
||||
/// Designated initializer.
|
||||
/// Takes ownership of @c codeRef.
|
||||
///
|
||||
/// Designated initializer
|
||||
/// Takes ownership of the codeRef reference.
|
||||
///
|
||||
/// @param codeRef a SecStaticCodeRef or SecCodeRef representing a binary.
|
||||
/// @return an initialized SNTCodesignChecker if the binary is validly signed, nil otherwise.
|
||||
///
|
||||
- (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef;
|
||||
|
||||
/// Initialize an @c SNTCodesignChecker with a binary on disk.
|
||||
/// Returns nil if @c binaryPath does not exist, is not a binary or is not codesigned.
|
||||
///
|
||||
/// Convenience initializer for a binary on disk.
|
||||
///
|
||||
/// @param binaryPath A binary file on disk
|
||||
/// @return an initialized SNTCodesignChecker if file is a binary and is signed, nil otherwise.
|
||||
///
|
||||
- (instancetype)initWithBinaryPath:(NSString *)binaryPath;
|
||||
|
||||
/// Initialize an @c SNTCodesignChecker with the PID of a running process.
|
||||
///
|
||||
/// Convenience initializer for a binary that is running, by its process ID.
|
||||
///
|
||||
/// @param PID Id of a running process.
|
||||
/// @return an initialized SNTCodesignChecker if binary is signed, nil otherwise.
|
||||
///
|
||||
- (instancetype)initWithPID:(pid_t)PID;
|
||||
|
||||
/// Initialize an @c SNTCodesignChecker for the currently-running process.
|
||||
///
|
||||
/// Convenience initializer for the currently running process.
|
||||
///
|
||||
/// @return an initialized SNTCodesignChecker if current binary is signed, nil otherwise.
|
||||
///
|
||||
- (instancetype)initWithSelf;
|
||||
|
||||
/// Returns true if the binary represented by @c otherChecker has signing information that matches
|
||||
/// this binary.
|
||||
///
|
||||
/// Compares the signatures of the binaries represented by this SNTCodesignChecker and
|
||||
/// @c otherChecker.
|
||||
///
|
||||
/// If both binaries are correctly signed and the leaf signatures are identical.
|
||||
///
|
||||
/// @return YES if both binaries are signed with the same leaf certificate.
|
||||
///
|
||||
- (BOOL)signingInformationMatches:(SNTCodesignChecker *)otherChecker;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -19,36 +19,41 @@
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
|
||||
// kStaticSigningFlags are the flags used when validating signatures on disk.
|
||||
//
|
||||
// Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
|
||||
// up validation (see below) but does mean images, plists, etc will not be checked and modifying
|
||||
// these will not be considered invalid. To ensure any code inside the binary is still checked,
|
||||
// we check nested code.
|
||||
//
|
||||
// Timings with different flags:
|
||||
// Checking Xcode 5.1.1 bundle:
|
||||
// kSecCSDefaultFlags: 3.895s
|
||||
// kSecCSDoNotValidateResources: 0.013s
|
||||
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
|
||||
//
|
||||
// Checking Google Chrome 36.0.1985.143 bundle:
|
||||
// kSecCSDefaultFlags: 0.529s
|
||||
// kSecCSDoNotValidateResources: 0.032s
|
||||
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
|
||||
//
|
||||
/**
|
||||
* kStaticSigningFlags are the flags used when validating signatures on disk.
|
||||
*
|
||||
* Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
|
||||
* up validation (see below) but does mean images, plists, etc will not be checked and modifying
|
||||
* these will not be considered invalid. To ensure any code inside the binary is still checked,
|
||||
* we check nested code.
|
||||
*
|
||||
* Timings with different flags:
|
||||
* Checking Xcode 5.1.1 bundle:
|
||||
* kSecCSDefaultFlags: 3.895s
|
||||
* kSecCSDoNotValidateResources: 0.013s
|
||||
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
|
||||
*
|
||||
* Checking Google Chrome 36.0.1985.143 bundle:
|
||||
* kSecCSDefaultFlags: 0.529s
|
||||
* kSecCSDoNotValidateResources: 0.032s
|
||||
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
|
||||
*/
|
||||
const SecCSFlags kStaticSigningFlags = kSecCSDoNotValidateResources | kSecCSCheckNestedCode;
|
||||
|
||||
// kSigningFlags are the flags used when validating signatures for running binaries.
|
||||
//
|
||||
// No special flags needed currently.
|
||||
/**
|
||||
* kSigningFlags are the flags used when validating signatures for running binaries.
|
||||
*
|
||||
* No special flags needed currently.
|
||||
*/
|
||||
const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
|
||||
|
||||
@implementation SNTCodesignChecker {
|
||||
/// Array of @c SNTCertificate's representing the chain of certs this executable was signed with.
|
||||
NSMutableArray *_certificates;
|
||||
}
|
||||
@interface SNTCodesignChecker ()
|
||||
/// Array of @c SNTCertificate's representing the chain of certs this executable was signed with.
|
||||
@property NSMutableArray *certificates;
|
||||
@end
|
||||
|
||||
@implementation SNTCodesignChecker
|
||||
|
||||
#pragma mark Init/dealloc
|
||||
|
||||
@@ -81,12 +86,13 @@ const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
if (!certs) return nil;
|
||||
|
||||
// Wrap SecCertificateRef objects in SNTCertificate and put in a new NSArray
|
||||
_certificates = [[NSMutableArray alloc] initWithCapacity:certs.count];
|
||||
NSMutableArray *mutableCerts = [[NSMutableArray alloc] initWithCapacity:certs.count];
|
||||
for (int i = 0; i < certs.count; ++i) {
|
||||
SecCertificateRef certRef = (__bridge SecCertificateRef)certs[i];
|
||||
SNTCertificate *newCert = [[SNTCertificate alloc] initWithSecCertificateRef:certRef];
|
||||
[_certificates addObject:newCert];
|
||||
[mutableCerts addObject:newCert];
|
||||
}
|
||||
_certificates = [mutableCerts copy];
|
||||
|
||||
_codeRef = codeRef;
|
||||
CFRetain(_codeRef);
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
#import "SNTCodesignChecker.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
|
||||
// kStaticSigningFlags are the flags used when validating signatures on disk.
|
||||
//
|
||||
// Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
|
||||
// up validation (see below) but does mean images, plists, etc will not be checked and modifying
|
||||
// these will not be considered invalid. To ensure any code inside the binary is still checked,
|
||||
// we check nested code.
|
||||
//
|
||||
// Timings with different flags:
|
||||
// Checking Xcode 5.1.1 bundle:
|
||||
// kSecCSDefaultFlags: 3.895s
|
||||
// kSecCSDoNotValidateResources: 0.013s
|
||||
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
|
||||
//
|
||||
// Checking Google Chrome 36.0.1985.143 bundle:
|
||||
// kSecCSDefaultFlags: 0.529s
|
||||
// kSecCSDoNotValidateResources: 0.032s
|
||||
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
|
||||
//
|
||||
const SecCSFlags kStaticSigningFlags = kSecCSDoNotValidateResources | kSecCSCheckNestedCode;
|
||||
|
||||
// kSigningFlags are the flags used when validating signatures for running binaries.
|
||||
//
|
||||
// No special flags needed currently.
|
||||
const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
|
||||
|
||||
@implementation SNTCodesignChecker
|
||||
|
||||
#pragma mark Init/dealloc
|
||||
|
||||
- (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_codeRef = codeRef;
|
||||
CFRetain(_codeRef);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBinaryPath:(NSString *)binaryPath {
|
||||
SecStaticCodeRef codeRef = NULL;
|
||||
|
||||
// Get SecStaticCodeRef for binary
|
||||
if (SecStaticCodeCreateWithPath((__bridge CFURLRef)[NSURL fileURLWithPath:binaryPath
|
||||
isDirectory:NO],
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
self = [self initWithSecStaticCodeRef:codeRef];
|
||||
} else {
|
||||
self = nil;
|
||||
}
|
||||
|
||||
if (codeRef) CFRelease(codeRef);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithPID:(pid_t)PID {
|
||||
SecCodeRef codeRef = NULL;
|
||||
NSDictionary *attributes = @{(__bridge NSString *)kSecGuestAttributePid: @(PID)};
|
||||
|
||||
if (SecCodeCopyGuestWithAttributes(NULL,
|
||||
(__bridge CFDictionaryRef)attributes,
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
self = [self initWithSecStaticCodeRef:codeRef];
|
||||
} else {
|
||||
self = nil;
|
||||
}
|
||||
|
||||
if (codeRef) CFRelease(codeRef);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSelf {
|
||||
SecCodeRef codeSelf = NULL;
|
||||
if (SecCodeCopySelf(kSecCSDefaultFlags, &codeSelf) == errSecSuccess) {
|
||||
self = [self initWithSecStaticCodeRef:codeSelf];
|
||||
} else {
|
||||
self = nil;
|
||||
}
|
||||
|
||||
if (codeSelf) CFRelease(codeSelf);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (_codeRef) CFRelease(_codeRef);
|
||||
}
|
||||
|
||||
#pragma mark Validate
|
||||
|
||||
- (OSStatus)validate {
|
||||
return [self validateWithRequirement:NULL];
|
||||
}
|
||||
|
||||
- (OSStatus)validateAppleAnchor {
|
||||
SecRequirementRef req = NULL;
|
||||
SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &req);
|
||||
return [self validateWithRequirement:req];
|
||||
}
|
||||
|
||||
- (OSStatus)validateAppleAnchorGeneric {
|
||||
SecRequirementRef req = NULL;
|
||||
SecRequirementCreateWithString(CFSTR("anchor apple generic"), kSecCSDefaultFlags, &req);
|
||||
return [self validateWithRequirement:req];
|
||||
}
|
||||
|
||||
- (OSStatus)validateWithRequirement:(SecRequirementRef)requirement {
|
||||
// Validate the binary and save the return code.
|
||||
if (CFGetTypeID(self.codeRef) == SecStaticCodeGetTypeID()) {
|
||||
return SecStaticCodeCheckValidity(self.codeRef, kStaticSigningFlags, requirement);
|
||||
} else if (CFGetTypeID(self.codeRef) == SecCodeGetTypeID()) {
|
||||
return SecCodeCheckValidity((SecCodeRef)self.codeRef, kSigningFlags, requirement);
|
||||
} else {
|
||||
return errSecCSSignatureNotVerifiable;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Description
|
||||
|
||||
- (NSString *)description {
|
||||
NSString *retStr;
|
||||
if (CFGetTypeID(self.codeRef) == SecStaticCodeGetTypeID()) {
|
||||
retStr = @"On-disk binary, ";
|
||||
} else {
|
||||
retStr = @"In-memory binary, ";
|
||||
}
|
||||
|
||||
if ([self validate] == errSecSuccess) {
|
||||
[retStr appendFormat:@"signed by %@, ", self.leafCertificate.orgName];
|
||||
} else {
|
||||
[retStr appendFormat:@"unsigned, "];
|
||||
}
|
||||
|
||||
[retStr appendFormat:@"located at: %@", self.binaryPath];
|
||||
|
||||
return retStr;
|
||||
}
|
||||
|
||||
#pragma mark Public accessors
|
||||
|
||||
- (NSDictionary *)signingInformation {
|
||||
static NSDictionary *signingInformation = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// Get dictionary of signing information for binary
|
||||
CFDictionaryRef signingDict = NULL;
|
||||
SecCodeCopySigningInformation(self.codeRef, kSecCSSigningInformation, &signingDict);
|
||||
signingInformation = CFBridgingRelease(signingDict);
|
||||
});
|
||||
return signingInformation;
|
||||
}
|
||||
|
||||
- (NSArray *)certificates {
|
||||
static NSArray *certificates = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// Get array of certificates, wrap each one in a SNTCertificate and store in a new array.
|
||||
NSArray *certs = self.signingInformation[(__bridge NSString *)kSecCodeInfoCertificates];
|
||||
|
||||
NSMutableArray *tempCerts = [[NSMutableArray alloc] initWithCapacity:certs.count];
|
||||
for (id cert in certs) {
|
||||
SNTCertificate *newCert =
|
||||
[[SNTCertificate alloc] initWithSecCertificateRef:(SecCertificateRef)cert];
|
||||
if (newCert) [tempCerts addObject:newCert];
|
||||
}
|
||||
certificates = [tempCerts copy];
|
||||
});
|
||||
return certificates;
|
||||
}
|
||||
|
||||
- (SNTCertificate *)leafCertificate {
|
||||
return [self.certificates firstObject];
|
||||
}
|
||||
|
||||
- (NSString *)binaryPath {
|
||||
CFURLRef path;
|
||||
OSStatus status = SecCodeCopyPath(_codeRef, kSecCSDefaultFlags, &path);
|
||||
NSURL *pathURL = CFBridgingRelease(path);
|
||||
if (status != errSecSuccess) return nil;
|
||||
return [pathURL path];
|
||||
}
|
||||
|
||||
#pragma mark Comparisons
|
||||
|
||||
- (BOOL)signingChainMatches:(SNTCodesignChecker *)otherChecker {
|
||||
return [self.certificates isEqual:otherChecker.certificates];
|
||||
}
|
||||
|
||||
- (BOOL)teamSigningMatches:(SNTCodesignChecker *)otherChecker {
|
||||
SNTCertificate *myLeaf = [self.certificates firstObject];
|
||||
SNTCertificate *otherLeaf = [otherChecker.certificates firstObject];
|
||||
|
||||
return ([myLeaf.orgUnit isEqual:otherLeaf.orgUnit] &&
|
||||
[self validateAppleAnchorGeneric] &&
|
||||
[otherChecker validateAppleAnchorGeneric]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -15,11 +15,10 @@
|
||||
#ifndef SANTA__COMMON__COMMONENUMS_H
|
||||
#define SANTA__COMMON__COMMONENUMS_H
|
||||
|
||||
// These enums are used in various places throughout the Santa client code.
|
||||
// The integer values are also stored in the database and so shouldn't be changed.
|
||||
|
||||
// Each enum contains an _UNKNOWN and a _MAX value, which the valid values must be between so that
|
||||
// the code can easily verify valid values.
|
||||
///
|
||||
/// These enums are used in various places throughout the Santa client code.
|
||||
/// The integer values are also stored in the database and so shouldn't be changed.
|
||||
///
|
||||
|
||||
typedef enum {
|
||||
RULETYPE_UNKNOWN,
|
||||
@@ -56,9 +55,12 @@ typedef enum {
|
||||
EVENTSTATE_ALLOW_UNKNOWN = 1,
|
||||
EVENTSTATE_ALLOW_BINARY = 2,
|
||||
EVENTSTATE_ALLOW_CERTIFICATE = 3,
|
||||
EVENTSTATE_BLOCK_UNKNOWN = 4,
|
||||
EVENTSTATE_BLOCK_BINARY = 5,
|
||||
EVENTSTATE_BLOCK_CERTIFICATE = 6,
|
||||
EVENTSTATE_ALLOW_SCOPE = 4,
|
||||
|
||||
EVENTSTATE_BLOCK_UNKNOWN = 5,
|
||||
EVENTSTATE_BLOCK_BINARY = 6,
|
||||
EVENTSTATE_BLOCK_CERTIFICATE = 7,
|
||||
EVENTSTATE_BLOCK_SCOPE = 8,
|
||||
|
||||
EVENTSTATE_MAX
|
||||
} santa_eventstate_t;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,48 +14,125 @@
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
|
||||
/// Singleton that provides an interface for managing configuration values on disk
|
||||
/// n.b: This class is designed as a singleton but is not enforced.
|
||||
///
|
||||
/// Singleton that provides an interface for managing configuration values on disk
|
||||
/// @note This class is designed as a singleton but that is not strictly enforced.
|
||||
///
|
||||
@interface SNTConfigurator : NSObject
|
||||
|
||||
/// The operating mode
|
||||
/// Default config file path
|
||||
extern NSString * const kDefaultConfigFilePath;
|
||||
|
||||
#pragma mark - Daemon Settings
|
||||
|
||||
///
|
||||
/// The operating mode.
|
||||
///
|
||||
@property santa_clientmode_t clientMode;
|
||||
|
||||
/// If YES, debug logging is enabled
|
||||
@property(readonly) BOOL debugLogging;
|
||||
///
|
||||
/// 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
|
||||
@property(readonly) NSString *machineIDOverride;
|
||||
///
|
||||
/// If set, this over-rides the default machine ID used for syncing.
|
||||
///
|
||||
@property(readonly) NSString *machineID;
|
||||
|
||||
# pragma mark Server Auth Settings
|
||||
|
||||
/// If set, this is valid PEM containing one or more certificates to be used to evaluate the
|
||||
/// server's SSL chain, overriding the list of trusted CAs distributed with the OS.
|
||||
///
|
||||
/// If set, this is valid PEM containing one or more certificates to be used to evaluate the
|
||||
/// server's SSL chain, overriding the list of trusted CAs distributed with the OS.
|
||||
///
|
||||
@property(readonly) NSData *syncServerAuthRootsData;
|
||||
|
||||
/// This property is the same as the above but is a file on disk containing the PEM data.
|
||||
///
|
||||
/// This property is the same as the above but is a file on disk containing the PEM data.
|
||||
///
|
||||
@property(readonly) NSString *syncServerAuthRootsFile;
|
||||
|
||||
# pragma mark Client Auth Settings
|
||||
|
||||
/// If set, this is the Common Name of a certificate in the System keychain to be used for
|
||||
/// sync authentication. The corresponding private key must also be in the keychain.
|
||||
///
|
||||
/// If set, this contains the location of a PKCS#12 certificate to be used for sync authentication.
|
||||
///
|
||||
@property(readonly) NSString *syncClientAuthCertificateFile;
|
||||
|
||||
///
|
||||
/// Contains the password for the pkcs#12 certificate.
|
||||
///
|
||||
@property(readonly) NSString *syncClientAuthCertificatePassword;
|
||||
|
||||
///
|
||||
/// If set, this is the Common Name of a certificate in the System keychain to be used for
|
||||
/// sync authentication. The corresponding private key must also be in the keychain.
|
||||
///
|
||||
@property(readonly) NSString *syncClientAuthCertificateCn;
|
||||
|
||||
/// If set, this is the Issuer Name of a certificate in the System keychain to be used for
|
||||
/// sync authentication. The corresponding private key must also be in the keychain.
|
||||
///
|
||||
/// If set, this is the Issuer Name of a certificate in the System keychain to be used for
|
||||
/// sync authentication. The corresponding private key must also be in the keychain.
|
||||
///
|
||||
@property(readonly) NSString *syncClientAuthCertificateIssuer;
|
||||
|
||||
|
||||
/// Retrieve the initialized singleton configurator object
|
||||
///
|
||||
/// Retrieve an initialized singleton configurator object using the default file path.
|
||||
///
|
||||
+ (instancetype)configurator;
|
||||
|
||||
///
|
||||
/// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -15,24 +15,34 @@
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
|
||||
@interface SNTConfigurator ()
|
||||
@property NSString *configFilePath;
|
||||
@property NSMutableDictionary *configData;
|
||||
@end
|
||||
|
||||
@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";
|
||||
static NSString * const kClientAuthCertificateCNKey = @"ClientAuthCertificateCN";
|
||||
static NSString * const kClientAuthCertificateIssuerKey = @"ClientAuthCertificateIssuerCN";
|
||||
static NSString * const kServerAuthRootsDataKey = @"ServerAuthRootsData";
|
||||
static NSString * const kServerAuthRootsFileKey = @"ServerAuthRootsFile";
|
||||
static NSString * const kDebugLoggingKey = @"DebugLogging";
|
||||
static NSString * const kClientModeKey = @"ClientMode";
|
||||
|
||||
static NSString * const kMachineOwnerKey = @"MachineOwner";
|
||||
static NSString * const kMachineIDKey = @"MachineID";
|
||||
@@ -43,9 +53,10 @@ static NSString * const kMachineOwnerPlistKeyKey = @"MachineOwnerKey";
|
||||
static NSString * const kMachineIDPlistFileKey = @"MachineIDPlist";
|
||||
static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
|
||||
- (instancetype)init {
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configFilePath = filePath;
|
||||
[self reloadConfigData];
|
||||
}
|
||||
return self;
|
||||
@@ -57,17 +68,63 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
static SNTConfigurator *sharedConfigurator = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedConfigurator = [[SNTConfigurator alloc] init];
|
||||
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]];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificateFile {
|
||||
return self.configData[kClientAuthCertificateFileKey];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificatePassword {
|
||||
return self.configData[kClientAuthCertificatePasswordKey];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificateCn {
|
||||
return self.configData[kClientAuthCertificateCNKey];
|
||||
}
|
||||
@@ -85,67 +142,88 @@ 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 @"";
|
||||
}
|
||||
|
||||
- (BOOL)debugLogging {
|
||||
return [self.configData[kDebugLoggingKey] boolValue];
|
||||
}
|
||||
|
||||
- (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 || [machineId isEqual:@""]) {
|
||||
machineId = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
- (void)setClientMode:(santa_clientmode_t)newMode {
|
||||
if (newMode > CLIENTMODE_UNKNOWN && newMode < CLIENTMODE_MAX) {
|
||||
[self reloadConfigData];
|
||||
self.configData[kClientModeKey] = @(newMode);
|
||||
- (void)reloadConfigData {
|
||||
if (!self.configData) self.configData = [NSMutableDictionary dictionary];
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
if (![fm fileExistsAtPath:self.configFilePath]) return;
|
||||
|
||||
NSError *error;
|
||||
NSData *readData = [NSData dataWithContentsOfFile:self.configFilePath
|
||||
options:NSDataReadingMappedIfSafe
|
||||
error:&error];
|
||||
if (error) {
|
||||
LOGE(@"Could not read configuration file: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSDictionary *configData =
|
||||
[NSPropertyListSerialization propertyListWithData:readData
|
||||
options:kCFPropertyListImmutable
|
||||
format:NULL
|
||||
error:&error];
|
||||
if (error) {
|
||||
LOGE(@"Could not parse configuration file: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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:kConfigFilePath atomically:YES];
|
||||
}
|
||||
|
||||
- (void)reloadConfigData {
|
||||
_configData = [[NSDictionary dictionaryWithContentsOfFile:kConfigFilePath] mutableCopy];
|
||||
|
||||
if (!_configData) {
|
||||
_configData = [NSMutableDictionary dictionary];
|
||||
}
|
||||
[self.configData writeToFile:self.configFilePath atomically:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,6 +12,9 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// Simple function to check and drop root privileges.
|
||||
/// @return True if dropping was successful or unnecessary.
|
||||
BOOL DropRootPrivileges();
|
||||
///
|
||||
/// Simple function to check and drop root privileges.
|
||||
///
|
||||
/// @return YES if dropping was successful or unnecessary.
|
||||
///
|
||||
BOOL DropRootPrivileges();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -27,4 +27,4 @@ BOOL DropRootPrivileges() {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
128
Source/common/SNTFileInfo.h
Normal file
128
Source/common/SNTFileInfo.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/// 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.
|
||||
|
||||
///
|
||||
/// Represents a binary on disk, providing access to details about that binary
|
||||
/// such as the SHA-1, SHA-256, Info.plist and the Mach-O data.
|
||||
///
|
||||
@interface SNTFileInfo : NSObject
|
||||
|
||||
///
|
||||
/// Designated initializer.
|
||||
///
|
||||
/// @param path The path of the file this instance is to represent. The path will be
|
||||
/// converted to an absolute, standardized path if it isn't already.
|
||||
///
|
||||
- (instancetype)initWithPath:(NSString *)path;
|
||||
|
||||
///
|
||||
/// @return Path of this file.
|
||||
///
|
||||
- (NSString *)path;
|
||||
|
||||
///
|
||||
/// @return SHA-1 hash of this binary.
|
||||
///
|
||||
- (NSString *)SHA1;
|
||||
|
||||
///
|
||||
/// @return SHA-256 hash of this binary.
|
||||
///
|
||||
- (NSString *)SHA256;
|
||||
|
||||
///
|
||||
/// @return The type of Mach-O file, one of:
|
||||
/// Dynamic Library, Kernel Extension, Fat Binary or Thin Binary.
|
||||
///
|
||||
- (NSString *)machoType;
|
||||
|
||||
///
|
||||
/// @return The architectures included in this binary (e.g. x86_64, ppc).
|
||||
///
|
||||
- (NSArray *)architectures;
|
||||
|
||||
///
|
||||
/// @return YES if this file is a Mach-O file.
|
||||
///
|
||||
- (BOOL)isMachO;
|
||||
|
||||
///
|
||||
/// @return YES if this file contains multiple architectures.
|
||||
///
|
||||
- (BOOL)isFat;
|
||||
|
||||
///
|
||||
/// @return YES if this file is an executable Mach-O file.
|
||||
///
|
||||
- (BOOL)isExecutable;
|
||||
|
||||
///
|
||||
/// @return YES if this file is a dynamic library.
|
||||
///
|
||||
- (BOOL)isDylib;
|
||||
|
||||
///
|
||||
/// @return YES if this file is a kernel extension.
|
||||
///
|
||||
- (BOOL)isKext;
|
||||
|
||||
///
|
||||
/// @return YES if this file is a script (e.g. it begins #!).
|
||||
///
|
||||
- (BOOL)isScript;
|
||||
|
||||
///
|
||||
/// @return An NSBundle if this file is part of a bundle.
|
||||
///
|
||||
- (NSBundle *)bundle;
|
||||
|
||||
///
|
||||
/// @return The path to the bundle this file is a part of, if any.
|
||||
///
|
||||
- (NSString *)bundlePath;
|
||||
|
||||
///
|
||||
/// @return Either the Info.plist in the bundle this file is part of, or an embedded plist if there
|
||||
/// is one. In the odd case that a file has both an embedded Info.plist and is part of a bundle,
|
||||
/// the Info.plist from the bundle will be returned.
|
||||
///
|
||||
- (NSDictionary *)infoPlist;
|
||||
|
||||
///
|
||||
/// @return the CFBundleIdentifier from this file's Info.plist.
|
||||
///
|
||||
- (NSString *)bundleIdentifier;
|
||||
|
||||
///
|
||||
/// @return the CFBundleName from this file's Info.plist.
|
||||
///
|
||||
- (NSString *)bundleName;
|
||||
|
||||
///
|
||||
/// @return the CFBundleVersion from this file's Info.plist.
|
||||
///
|
||||
- (NSString *)bundleVersion;
|
||||
|
||||
///
|
||||
/// @return the CFBundleShortVersionString from this file's Info.plist.
|
||||
///
|
||||
- (NSString *)bundleShortVersionString;
|
||||
|
||||
///
|
||||
/// @return any URLs this file may have been downloaded from, using the
|
||||
/// @c com.apple.metadata:kMDItemWhereFroms extended attribute.
|
||||
///
|
||||
- (NSArray *)downloadURLs;
|
||||
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,29 +12,54 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "SNTBinaryInfo.h"
|
||||
#import "SNTFileInfo.h"
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
@interface SNTBinaryInfo ()
|
||||
@interface SNTFileInfo ()
|
||||
@property NSString *path;
|
||||
@property NSData *fileData;
|
||||
@property NSBundle *bundleRef;
|
||||
@property NSDictionary *infoDict;
|
||||
@end
|
||||
|
||||
@implementation SNTBinaryInfo
|
||||
@implementation SNTFileInfo
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_path = path;
|
||||
// Convert to absolute, standardized path
|
||||
path = [path stringByResolvingSymlinksInPath];
|
||||
if (![path isAbsolutePath]) {
|
||||
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
path = [cwd stringByAppendingPathComponent:path];
|
||||
}
|
||||
path = [path stringByStandardizingPath];
|
||||
|
||||
_fileData = [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:nil];
|
||||
// Determine if file exists.
|
||||
// If path is actually a directory, check to see if it's a bundle and has a CFBundleExecutable.
|
||||
BOOL directory;
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&directory]) {
|
||||
return nil;
|
||||
} else if (directory) {
|
||||
NSString *infoPath = [path stringByAppendingPathComponent:@"Contents/Info.plist"];
|
||||
NSDictionary *d = [NSDictionary dictionaryWithContentsOfFile:infoPath];
|
||||
if (d && d[@"CFBundleExecutable"]) {
|
||||
path = [path stringByAppendingPathComponent:@"Contents/MacOS"];
|
||||
_path = [path stringByAppendingPathComponent:d[@"CFBundleExecutable"]];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
_path = path;
|
||||
}
|
||||
|
||||
_fileData = [NSData dataWithContentsOfFile:_path options:NSDataReadingMappedIfSafe error:nil];
|
||||
if (!_fileData) return nil;
|
||||
}
|
||||
|
||||
@@ -54,6 +79,18 @@
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)SHA256 {
|
||||
unsigned char sha2[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha2);
|
||||
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH *2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha2[i]];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)machoType {
|
||||
if ([self isDylib]) { return @"Dynamic Library"; }
|
||||
if ([self isKext]) { return @"Kernel Extension"; }
|
||||
@@ -148,26 +185,26 @@
|
||||
|
||||
# pragma mark Bundle Information
|
||||
|
||||
/**
|
||||
* Try and determine the bundle that the represented executable is contained within, if any.
|
||||
*
|
||||
* Rationale: An NSBundle has a method executablePath for discovering the main binary within a
|
||||
* bundle but provides no way to get an NSBundle object when only the executablePath is known. Also,
|
||||
* a bundle can contain multiple binaries within the MacOS folder and we want any of these to count
|
||||
* as being part of the bundle.
|
||||
*
|
||||
* This method relies on executable bundles being laid out as follows:
|
||||
*
|
||||
*@code
|
||||
* Bundle.app/
|
||||
* Contents/
|
||||
* MacOS/
|
||||
* executable
|
||||
*@endcode
|
||||
*
|
||||
* If @c self.path is the full path to @c executable above, this method would return an
|
||||
* NSBundle reference for Bundle.app.
|
||||
*/
|
||||
///
|
||||
/// Try and determine the bundle that the represented executable is contained within, if any.
|
||||
///
|
||||
/// Rationale: An NSBundle has a method executablePath for discovering the main binary within a
|
||||
/// bundle but provides no way to get an NSBundle object when only the executablePath is known. Also,
|
||||
/// a bundle can contain multiple binaries within the MacOS folder and we want any of these to count
|
||||
/// as being part of the bundle.
|
||||
///
|
||||
/// This method relies on executable bundles being laid out as follows:
|
||||
///
|
||||
/// @code
|
||||
/// Bundle.app/
|
||||
/// Contents/
|
||||
/// MacOS/
|
||||
/// executable
|
||||
/// @endcode
|
||||
///
|
||||
/// If @c self.path is the full path to @c executable above, this method would return an
|
||||
/// NSBundle reference for Bundle.app.
|
||||
///
|
||||
- (NSBundle *)bundle {
|
||||
if (self.bundleRef) return self.bundleRef;
|
||||
|
||||
@@ -220,11 +257,38 @@
|
||||
return [[self infoPlist] objectForKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
- (NSArray *)downloadURLs {
|
||||
char *path = (char *)[self.path fileSystemRepresentation];
|
||||
size_t size = getxattr(path, "com.apple.metadata:kMDItemWhereFroms", NULL, 0, 0, 0);
|
||||
char *value = malloc(size);
|
||||
if (!value) return nil;
|
||||
|
||||
if (getxattr(path, "com.apple.metadata:kMDItemWhereFroms", value, size, 0, 0) == -1) {
|
||||
free(value);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = [NSData dataWithBytes:value length:size];
|
||||
free(value);
|
||||
|
||||
if (data) {
|
||||
NSArray *urls = [NSPropertyListSerialization propertyListWithData:data
|
||||
options:NSPropertyListImmutable
|
||||
format:NULL
|
||||
error:NULL];
|
||||
return urls;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
# pragma mark Internal Methods
|
||||
|
||||
/// Look through the file for the first mach_header. If the file is thin, this will be the
|
||||
/// header at the beginning of the file. If the file is fat, it will be the first
|
||||
/// architecture-specific header.
|
||||
///
|
||||
/// Look through the file for the first mach_header. If the file is thin, this will be the
|
||||
/// header at the beginning of the file. If the file is fat, it will be the first
|
||||
/// architecture-specific header.
|
||||
///
|
||||
- (struct mach_header *)firstMachHeader {
|
||||
if (![self isMachO]) return NULL;
|
||||
|
||||
@@ -261,8 +325,10 @@
|
||||
return (header->magic == FAT_MAGIC || header->magic == FAT_CIGAM);
|
||||
}
|
||||
|
||||
/// Wrap subdataWithRange: in a @try/@catch, returning nil on exception.
|
||||
/// Useful for when the range is beyond the end of the file.
|
||||
///
|
||||
/// Wrap @c subdataWithRange: in a @@try/@@catch, returning nil on exception.
|
||||
/// Useful for when the range is beyond the end of the file.
|
||||
///
|
||||
- (NSData *)safeSubdataWithRange:(NSRange)range {
|
||||
@try {
|
||||
return [self.fileData subdataWithRange:range];
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,16 +12,16 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
///
|
||||
/// Common defines between kernel <-> userspace
|
||||
///
|
||||
|
||||
#ifndef SANTA__COMMON__KERNELCOMMON_H
|
||||
#define SANTA__COMMON__KERNELCOMMON_H
|
||||
|
||||
// Defines the lengths of paths and SHA-1's passed around.
|
||||
#define MAX_PATH_LEN 1024
|
||||
#define MAX_SHA1_LEN 20
|
||||
#define MAX_SHA1_STRING 41
|
||||
#define MAX_VNODE_ID_STR 21
|
||||
// Defines the lengths of paths and Vnode IDs passed around.
|
||||
#define MAX_PATH_LEN 1024 // ==PATH_LEN from syslimits.h
|
||||
#define MAX_VNODE_ID_STR 21 // digits in UINT64_MAX + 1 for NULL-terminator
|
||||
|
||||
// Defines the name of the userclient class and the driver bundle ID.
|
||||
#define USERCLIENT_CLASS "com_google_SantaDriver"
|
||||
@@ -30,7 +30,6 @@
|
||||
// List of methods supported by the driver.
|
||||
enum SantaDriverMethods {
|
||||
kSantaUserClientOpen,
|
||||
kSantaUserClientClose,
|
||||
kSantaUserClientAllowBinary,
|
||||
kSantaUserClientDenyBinary,
|
||||
kSantaUserClientClearCache,
|
||||
@@ -58,14 +57,17 @@ typedef enum {
|
||||
ACTION_ERROR = 99,
|
||||
} santa_action_t;
|
||||
|
||||
#define CHECKBW_RESPONSE_VALID(x) (x == ACTION_RESPOND_CHECKBW_ALLOW || \
|
||||
x == ACTION_RESPOND_CHECKBW_DENY)
|
||||
|
||||
// Message struct that is sent down the IODataQueue.
|
||||
typedef struct {
|
||||
santa_action_t action;
|
||||
uint64_t vnode_id;
|
||||
uid_t userId;
|
||||
pid_t pid;
|
||||
char sha1[MAX_SHA1_STRING];
|
||||
pid_t ppid;
|
||||
char path[MAX_PATH_LEN];
|
||||
uint64_t vnode_id;
|
||||
} santa_message_t;
|
||||
|
||||
#endif // SANTA__COMMON__KERNELCOMMON_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,7 +12,9 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
///
|
||||
/// Logging definitions, for both kernel and user space.
|
||||
///
|
||||
|
||||
#ifndef SANTA__COMMON__LOGGING_H
|
||||
#define SANTA__COMMON__LOGGING_H
|
||||
@@ -35,11 +37,14 @@
|
||||
#define LOG_LEVEL_INFO 3
|
||||
#define LOG_LEVEL_DEBUG 4
|
||||
|
||||
/// Logging function.
|
||||
/// level is one of the levels defined above
|
||||
/// error is the destination a FILE, generally should be stdout or stderr
|
||||
/// format is the printf style format string
|
||||
/// ... is the arguments to format.
|
||||
///
|
||||
/// Logging function.
|
||||
///
|
||||
/// @param level one of the levels defined above
|
||||
/// @param destination a FILE, generally should be stdout or stderr
|
||||
/// @param format the printf style format string
|
||||
/// @param ... the arguments to format.
|
||||
///
|
||||
void logMessage(int level, FILE *destination, NSString *format, ...);
|
||||
|
||||
/// Simple logging macros
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#import "SNTLogging.h"
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static int logLevel = LOG_LEVEL_DEBUG; // default to info
|
||||
#else
|
||||
@@ -35,7 +33,7 @@ void logMessage(int level, FILE *destination, NSString *format, ...) {
|
||||
binaryName = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
// If debug logging is enabled, the process must be restarted.
|
||||
if ([[SNTConfigurator configurator] debugLogging]) {
|
||||
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--debug"]) {
|
||||
logLevel = LOG_LEVEL_DEBUG;
|
||||
}
|
||||
});
|
||||
@@ -60,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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCertificate;
|
||||
|
||||
/// An SNTEvent is created when Santa is making a decision about an execution request.
|
||||
/// All of the information required to make that decision, log it, notify the user etc. must be
|
||||
/// encapsulated within this class.
|
||||
@interface SNTNotificationMessage : NSObject<NSSecureCoding>
|
||||
|
||||
/// The path of the binary that was blocked.
|
||||
@property(copy) NSString *path;
|
||||
|
||||
/// The SHA-1 of the binary that was blocked.
|
||||
@property(copy) NSString *SHA1;
|
||||
|
||||
/// An array of @c SNTCertificate objects representing the certificate chain the binary was signed with.
|
||||
@property(copy) NSArray *certificates;
|
||||
|
||||
/// A custom message to display to the user when blocking this binary, if any.
|
||||
@property(copy) NSString *customMessage;
|
||||
|
||||
// A convenience accessor to the first certificate in @c certificates.
|
||||
@property(readonly) SNTCertificate *leafCertificate;
|
||||
|
||||
@end
|
||||
@@ -1,55 +0,0 @@
|
||||
/// Copyright 2014 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 "SNTNotificationMessage.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
@implementation SNTNotificationMessage
|
||||
|
||||
static NSString *const kPathKey = @"path";
|
||||
static NSString *const kSHA1Key = @"sha1";
|
||||
static NSString *const kCertificatesKey = @"certificates";
|
||||
static NSString *const kCustomMessageKey = @"custommessage";
|
||||
|
||||
#pragma mark NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.path forKey:kPathKey];
|
||||
[coder encodeObject:self.SHA1 forKey:kSHA1Key];
|
||||
[coder encodeObject:self.customMessage forKey:kCustomMessageKey];
|
||||
[coder encodeObject:self.certificates forKey:kCertificatesKey];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
_path = [decoder decodeObjectOfClass:[NSString class] forKey:kPathKey];
|
||||
_SHA1 = [decoder decodeObjectOfClass:[NSString class] forKey:kSHA1Key];
|
||||
_customMessage = [decoder decodeObjectOfClass:[NSString class] forKey:kCustomMessageKey];
|
||||
|
||||
NSSet *certClasses = [NSSet setWithObjects:[NSArray class], [SNTCertificate class], nil];
|
||||
_certificates = [decoder decodeObjectOfClasses:certClasses forKey:kCertificatesKey];
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Calculated Properties
|
||||
|
||||
- (SNTCertificate *)leafCertificate {
|
||||
return [self.certificates firstObject];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,25 +14,37 @@
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
|
||||
/// Represents a Rule.
|
||||
///
|
||||
/// Represents a Rule.
|
||||
///
|
||||
@interface SNTRule : NSObject<NSSecureCoding>
|
||||
|
||||
/// The SHA-1 hash of the object this rule is for
|
||||
@property NSString *SHA1;
|
||||
///
|
||||
/// The hash of the object this rule is for
|
||||
///
|
||||
@property NSString *shasum;
|
||||
|
||||
/// The state of this rule
|
||||
///
|
||||
/// The state of this rule
|
||||
///
|
||||
@property santa_rulestate_t state;
|
||||
|
||||
/// The type of object this rule is for (binary, certificate)
|
||||
///
|
||||
/// The type of object this rule is for (binary, certificate)
|
||||
///
|
||||
@property santa_ruletype_t type;
|
||||
|
||||
/// A custom message that will be displayed if this rule blocks a binary from executing
|
||||
///
|
||||
/// A custom message that will be displayed if this rule blocks a binary from executing
|
||||
///
|
||||
@property NSString *customMsg;
|
||||
|
||||
/// Designated initializer.
|
||||
- (instancetype)initWithSHA1:(NSString *)SHA1
|
||||
state:(santa_rulestate_t)state
|
||||
type:(santa_ruletype_t)type
|
||||
customMsg:(NSString *)customMsg;
|
||||
///
|
||||
/// Designated initializer.
|
||||
///
|
||||
- (instancetype)initWithShasum:(NSString *)shasum
|
||||
state:(santa_rulestate_t)state
|
||||
type:(santa_ruletype_t)type
|
||||
customMsg:(NSString *)customMsg;
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,18 +16,13 @@
|
||||
|
||||
@implementation SNTRule
|
||||
|
||||
static NSString *const kSHA1Key = @"sha1";
|
||||
static NSString *const kStateKey = @"state";
|
||||
static NSString *const kTypeKey = @"type";
|
||||
static NSString *const kCustomMessageKey = @"custommsg";
|
||||
|
||||
- (instancetype)initWithSHA1:(NSString *)SHA1
|
||||
state:(santa_rulestate_t)state
|
||||
type:(santa_ruletype_t)type
|
||||
customMsg:(NSString *)customMsg {
|
||||
- (instancetype)initWithShasum:(NSString *)shasum
|
||||
state:(santa_rulestate_t)state
|
||||
type:(santa_ruletype_t)type
|
||||
customMsg:(NSString *)customMsg {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_SHA1 = SHA1;
|
||||
_shasum = shasum;
|
||||
_state = state;
|
||||
_type = type;
|
||||
_customMsg = customMsg;
|
||||
@@ -37,23 +32,30 @@ static NSString *const kCustomMessageKey = @"custommsg";
|
||||
|
||||
#pragma mark NSSecureCoding
|
||||
|
||||
#define ENCODE(obj, key) if (obj) [coder encodeObject:obj forKey:key]
|
||||
#define DECODE(cls, key) [decoder decodeObjectOfClass:[cls class] forKey:key]
|
||||
#define DECODEARRAY(cls, key) \
|
||||
[decoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [cls class], nil] \
|
||||
forKey:key]
|
||||
|
||||
+ (BOOL)supportsSecureCoding { return YES; }
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.SHA1 forKey:kSHA1Key];
|
||||
[coder encodeInt:self.state forKey:kStateKey];
|
||||
[coder encodeInt:self.type forKey:kTypeKey];
|
||||
[coder encodeObject:self.customMsg forKey:kCustomMessageKey];
|
||||
ENCODE(self.shasum, @"shasum");
|
||||
ENCODE(@(self.state), @"state");
|
||||
ENCODE(@(self.type), @"type");
|
||||
ENCODE(self.customMsg, @"custommsg");
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
NSSet *stringPlusNull = [NSSet setWithObjects:[NSString class], [NSNull class], nil];
|
||||
|
||||
_SHA1 = [decoder decodeObjectOfClass:[NSString class] forKey:kSHA1Key];
|
||||
_state = [decoder decodeIntForKey:kStateKey];
|
||||
_type = [decoder decodeIntForKey:kTypeKey];
|
||||
_customMsg = [decoder decodeObjectOfClasses:stringPlusNull forKey:kCustomMessageKey];
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_shasum = DECODE(NSString, @"shasum");
|
||||
_state = [DECODE(NSNumber, @"state") intValue];
|
||||
_type = [DECODE(NSNumber, @"type") intValue];
|
||||
_customMsg = DECODE(NSString, @"custommsg");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,27 +14,85 @@
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
|
||||
/// Represents an event stored in the database.
|
||||
///
|
||||
/// Represents an event stored in the database.
|
||||
///
|
||||
@interface SNTStoredEvent : NSObject<NSSecureCoding>
|
||||
|
||||
///
|
||||
/// An index for this event, empty unless the event came from the database.
|
||||
///
|
||||
@property NSNumber *idx;
|
||||
@property NSString *fileSHA1;
|
||||
|
||||
///
|
||||
/// The SHA-256 of the executed file.
|
||||
///
|
||||
@property NSString *fileSHA256;
|
||||
|
||||
///
|
||||
/// The full path of the executed file.
|
||||
///
|
||||
@property NSString *filePath;
|
||||
|
||||
///
|
||||
/// If the executed file was part of the bundle, this is the CFBundleName.
|
||||
///
|
||||
@property NSString *fileBundleName;
|
||||
|
||||
///
|
||||
/// If the executed file was part of the bundle, this is the CFBundleID.
|
||||
///
|
||||
@property NSString *fileBundleID;
|
||||
|
||||
///
|
||||
/// If the executed file was part of the bundle, this is the CFBundleVersion.
|
||||
///
|
||||
@property NSString *fileBundleVersion;
|
||||
|
||||
///
|
||||
/// If the executed file was part of the bundle, this is the CFBundleShortVersionString.
|
||||
///
|
||||
@property NSString *fileBundleVersionString;
|
||||
@property NSString *certSHA1;
|
||||
@property NSString *certCN;
|
||||
@property NSString *certOrg;
|
||||
@property NSString *certOU;
|
||||
@property NSDate *certValidFromDate;
|
||||
@property NSDate *certValidUntilDate;
|
||||
|
||||
///
|
||||
/// If the executed file was signed, this is an NSArray of SNTCertificate's
|
||||
/// representing the signing chain.
|
||||
///
|
||||
@property NSArray *signingChain;
|
||||
|
||||
///
|
||||
/// The user who executed the binary.
|
||||
///
|
||||
@property NSString *executingUser;
|
||||
|
||||
///
|
||||
/// The date and time the execution request was received by santad.
|
||||
///
|
||||
@property NSDate *occurrenceDate;
|
||||
|
||||
///
|
||||
/// The decision santad returned.
|
||||
///
|
||||
@property santa_eventstate_t decision;
|
||||
|
||||
///
|
||||
/// NSArray of logged in users when the decision was made.
|
||||
///
|
||||
@property NSArray *loggedInUsers;
|
||||
|
||||
///
|
||||
/// NSArray of sessions when the decision was made (e.g. nobody@console, nobody@ttys000).
|
||||
///
|
||||
@property NSArray *currentSessions;
|
||||
|
||||
///
|
||||
/// The process ID of the binary being executed.
|
||||
///
|
||||
@property NSNumber *pid;
|
||||
|
||||
///
|
||||
/// The parent process ID of the binary being executed.
|
||||
///
|
||||
@property NSNumber *ppid;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,75 +14,70 @@
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
@implementation SNTStoredEvent
|
||||
|
||||
#define ENCODE(obj, key) if (obj) [coder encodeObject:obj forKey:key]
|
||||
#define DECODE(cls, key) [decoder decodeObjectOfClass:[cls class] forKey:key]
|
||||
#define DECODEARRAY(cls, key) \
|
||||
[decoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [cls class], nil] \
|
||||
forKey:key]
|
||||
|
||||
+ (BOOL)supportsSecureCoding { return YES; }
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.idx forKey:@"idx"];
|
||||
[coder encodeObject:self.fileSHA1 forKey:@"fileSHA1"];
|
||||
[coder encodeObject:self.filePath forKey:@"filePath"];
|
||||
ENCODE(self.idx, @"idx");
|
||||
ENCODE(self.fileSHA256, @"fileSHA256");
|
||||
ENCODE(self.filePath, @"filePath");
|
||||
|
||||
if (self.fileBundleName) [coder encodeObject:self.fileBundleName forKey:@"fileBundleName"];
|
||||
if (self.fileBundleID) [coder encodeObject:self.fileBundleID forKey:@"fileBundleID"];
|
||||
if (self.fileBundleVersion) {
|
||||
[coder encodeObject:self.fileBundleVersion forKey:@"fileBundleVersion"];
|
||||
}
|
||||
if (self.fileBundleVersionString) {
|
||||
[coder encodeObject:self.fileBundleVersionString forKey:@"fileBundleVersionString"];
|
||||
}
|
||||
ENCODE(self.fileBundleName, @"fileBundleName");
|
||||
ENCODE(self.fileBundleID, @"fileBundleID");
|
||||
ENCODE(self.fileBundleVersion, @"fileBundleVersion");
|
||||
ENCODE(self.fileBundleVersionString, @"fileBundleVersionString");
|
||||
|
||||
if (self.certSHA1) [coder encodeObject:self.certSHA1 forKey:@"certSHA1"];
|
||||
if (self.certCN) [coder encodeObject:self.certCN forKey:@"certCN"];
|
||||
if (self.certOrg) [coder encodeObject:self.certOrg forKey:@"certOrg"];
|
||||
if (self.certOU) [coder encodeObject:self.certOU forKey:@"certOU"];
|
||||
if (self.certValidFromDate) {
|
||||
[coder encodeObject:self.certValidFromDate forKey:@"certValidFromDate"];
|
||||
}
|
||||
if (self.certValidUntilDate) {
|
||||
[coder encodeObject:self.certValidUntilDate forKey:@"certValidUntilDate"];
|
||||
}
|
||||
ENCODE(self.signingChain, @"signingChain");
|
||||
|
||||
[coder encodeObject:self.executingUser forKey:@"executingUser"];
|
||||
[coder encodeObject:self.occurrenceDate forKey:@"occurrenceDate"];
|
||||
[coder encodeInt:self.decision forKey:@"decision"];
|
||||
ENCODE(self.executingUser, @"executingUser");
|
||||
ENCODE(self.occurrenceDate, @"occurrenceDate");
|
||||
ENCODE(@(self.decision), @"decision");
|
||||
ENCODE(self.pid, @"pid");
|
||||
ENCODE(self.ppid, @"ppid");
|
||||
|
||||
if (self.loggedInUsers) [coder encodeObject:self.loggedInUsers forKey:@"loggedInUsers"];
|
||||
if (self.currentSessions) [coder encodeObject:self.currentSessions forKey:@"currentSessions"];
|
||||
ENCODE(self.loggedInUsers, @"loggedInUsers");
|
||||
ENCODE(self.currentSessions, @"currentSessions");
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
_idx = [decoder decodeObjectOfClass:[NSNumber class] forKey:@"idx"];
|
||||
_fileSHA1 = [decoder decodeObjectOfClass:[NSString class] forKey:@"fileSHA1"];
|
||||
_filePath = [decoder decodeObjectOfClass:[NSString class] forKey:@"filePath"];
|
||||
_fileBundleName = [decoder decodeObjectOfClass:[NSString class] forKey:@"fileBundleName"];
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_idx = DECODE(NSNumber, @"idx");
|
||||
_fileSHA256 = DECODE(NSString, @"fileSHA256");
|
||||
_filePath = DECODE(NSString, @"filePath");
|
||||
|
||||
_fileBundleID = [decoder decodeObjectOfClass:[NSString class] forKey:@"fileBundleID"];
|
||||
_fileBundleVersion = [decoder decodeObjectOfClass:[NSString class] forKey:@"fileBundleVersion"];
|
||||
_fileBundleVersionString =
|
||||
[decoder decodeObjectOfClass:[NSString class] forKey:@"fileBundleVersionString"];
|
||||
_certSHA1 = [decoder decodeObjectOfClass:[NSString class] forKey:@"certSHA1"];
|
||||
_certCN = [decoder decodeObjectOfClass:[NSString class] forKey:@"certCN"];
|
||||
_certOrg = [decoder decodeObjectOfClass:[NSString class] forKey:@"certOrg"];
|
||||
_certOU = [decoder decodeObjectOfClass:[NSString class] forKey:@"certOU"];
|
||||
_certValidFromDate = [decoder decodeObjectOfClass:[NSDate class] forKey:@"certValidFromDate"];
|
||||
_certValidUntilDate = [decoder decodeObjectOfClass:[NSDate class] forKey:@"certValidUntilDate"];
|
||||
_executingUser = [decoder decodeObjectOfClass:[NSString class] forKey:@"executingUser"];
|
||||
_occurrenceDate = [decoder decodeObjectOfClass:[NSDate class] forKey:@"occurrenceDate"];
|
||||
_decision = [decoder decodeIntForKey:@"decision"];
|
||||
_fileBundleName = DECODE(NSString, @"fileBundleName");
|
||||
_fileBundleID = DECODE(NSString, @"fileBundleID");
|
||||
_fileBundleVersion = DECODE(NSString, @"fileBundleVersion");
|
||||
_fileBundleVersionString = DECODE(NSString, @"fileBundleVersionString");
|
||||
|
||||
NSSet *stringAndArrayClasses = [NSSet setWithObjects:[NSArray class], [NSString class], nil];
|
||||
_loggedInUsers = [decoder decodeObjectOfClasses:stringAndArrayClasses forKey:@"loggedInUsers"];
|
||||
_currentSessions = [decoder decodeObjectOfClasses:stringAndArrayClasses
|
||||
forKey:@"currentSessions"];
|
||||
_signingChain = DECODEARRAY(SNTCertificate, @"signingChain");
|
||||
|
||||
_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");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(SNTStoredEvent *)other {
|
||||
if (other == self) return YES;
|
||||
if (![other isKindOfClass:[SNTStoredEvent class]]) return NO;
|
||||
return ([self.fileSHA1 isEqual:other.fileSHA1] &&
|
||||
return ([self.fileSHA256 isEqual:other.fileSHA256] &&
|
||||
[self.idx isEqual:other.idx]);
|
||||
}
|
||||
|
||||
@@ -90,13 +85,14 @@
|
||||
NSUInteger prime = 31;
|
||||
NSUInteger result = 1;
|
||||
result = prime * result + [self.idx hash];
|
||||
result = prime * result + [self.fileSHA1 hash];
|
||||
result = prime * result + [self.filePath hash];
|
||||
result = prime * result + [self.fileSHA256 hash];
|
||||
result = prime * result + [self.occurrenceDate hash];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"SNTStoredEvent[%@] with SHA-1: %@", self.idx, self.fileSHA1];
|
||||
return [NSString stringWithFormat:@"SNTStoredEvent[%@] with SHA-256: %@",
|
||||
self.idx, self.fileSHA256];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,17 +12,39 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// Simple class for fetching system information
|
||||
///
|
||||
/// Simple class for fetching system information
|
||||
///
|
||||
@interface SNTSystemInfo : NSObject
|
||||
|
||||
///
|
||||
/// @return System serial number
|
||||
///
|
||||
+ (NSString *)serialNumber;
|
||||
|
||||
///
|
||||
/// @return System hardware UUID
|
||||
///
|
||||
+ (NSString *)hardwareUUID;
|
||||
|
||||
///
|
||||
/// @return OS Version, e.g.: 10.10.2
|
||||
///
|
||||
+ (NSString *)osVersion;
|
||||
|
||||
///
|
||||
/// @return OS Build, e.g.: 14C109
|
||||
///
|
||||
+ (NSString *)osBuild;
|
||||
|
||||
///
|
||||
/// @return Short hostname
|
||||
///
|
||||
+ (NSString *)shortHostname;
|
||||
|
||||
///
|
||||
/// @return Long hostname
|
||||
///
|
||||
+ (NSString *)longHostname;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,76 +12,108 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/**
|
||||
* A validating XPC connection/listener which uses codesigning to validate that both ends of the
|
||||
* connection were signed by the same certificate chain.
|
||||
*
|
||||
* Example server started by @c launchd where the @c launchd job has a @c MachServices key:
|
||||
*
|
||||
*@code
|
||||
* SNTXPCConnection *conn = [[SNTXPCConnection alloc] initServerWithName:@"MyServer"];
|
||||
* conn.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyServerProtocol)];
|
||||
* conn.exportedObject = myObject;
|
||||
* conn.remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyClientProtocol)];
|
||||
* [conn resume];
|
||||
*@endcode
|
||||
*
|
||||
* Example client, connecting to above server:
|
||||
*
|
||||
*@code
|
||||
* SNTXPCConnection *conn = [[SNTXPCConnection alloc] initClientWithName:"MyServer" withOptions:0];
|
||||
* conn.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyClientProtocol)];
|
||||
* conn.exportedObject = myObject;
|
||||
* conn.remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyServerProtocol)];
|
||||
* conn.invalidationHandler = ^{ NSLog(@"Connection invalidated") };
|
||||
* [conn resume];
|
||||
*@endcode
|
||||
*
|
||||
* Either side can then send a message to the other with:
|
||||
*
|
||||
*@code
|
||||
* [conn.remoteObjectProxy selectorInRemoteInterface];
|
||||
*@endcode
|
||||
*
|
||||
* Note: messages are always delivered on a background thread!
|
||||
**/
|
||||
///
|
||||
/// A validating XPC connection/listener which uses codesigning to validate that both ends of the
|
||||
/// connection were signed by the same certificate chain.
|
||||
///
|
||||
/// Example server started by @c launchd where the @c launchd job has a @c MachServices key:
|
||||
///
|
||||
/// @code
|
||||
/// SNTXPCConnection *conn = [[SNTXPCConnection alloc] initServerWithName:@"MyServer"];
|
||||
/// conn.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyServerProtocol)];
|
||||
/// conn.exportedObject = myObject;
|
||||
/// conn.remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyClientProtocol)];
|
||||
/// [conn resume];
|
||||
/// @endcode
|
||||
///
|
||||
/// Example client, connecting to above server:
|
||||
///
|
||||
/// @code
|
||||
/// SNTXPCConnection *conn = [[SNTXPCConnection alloc] initClientWithName:"MyServer"
|
||||
/// withOptions:0];
|
||||
/// conn.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyClientProtocol)];
|
||||
/// conn.exportedObject = myObject;
|
||||
/// conn.remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyServerProtocol)];
|
||||
/// conn.invalidationHandler = ^{ NSLog(@"Connection invalidated") };
|
||||
/// [conn resume];
|
||||
/// @endcode
|
||||
///
|
||||
/// Either side can then send a message to the other with:
|
||||
///
|
||||
/// @code
|
||||
/// [conn.remoteObjectProxy selectorInRemoteInterface];
|
||||
/// @endcode
|
||||
///
|
||||
/// @note messages are always delivered on a background thread!
|
||||
///
|
||||
@interface SNTXPCConnection : NSObject<NSXPCListenerDelegate>
|
||||
|
||||
typedef void (^SNTXPCInvalidationBlock)(void);
|
||||
typedef void (^SNTXPCAcceptedBlock)(void);
|
||||
typedef void (^SNTXPCRejectedBlock)(void);
|
||||
|
||||
/// The interface the remote object should conform to.
|
||||
///
|
||||
/// The interface the remote object should conform to.
|
||||
///
|
||||
@property(retain) NSXPCInterface *remoteInterface;
|
||||
|
||||
/// A proxy to the object at the other end of the connection.
|
||||
/// *Warning*: Do not send a message to this object if you didn't set @c remoteInterface above
|
||||
/// before calling the @c resume method, doing so will throw an exception.
|
||||
///
|
||||
/// A proxy to the object at the other end of the connection.
|
||||
///
|
||||
/// @warning Do not send a message to this object if you didn't set @c remoteInterface above
|
||||
/// before calling the @c resume method. Doing so will throw an exception.
|
||||
///
|
||||
@property(readonly) id remoteObjectProxy;
|
||||
|
||||
/// The interface this object conforms to.
|
||||
///
|
||||
/// The interface this object exports.
|
||||
///
|
||||
@property(retain) NSXPCInterface *exportedInterface;
|
||||
|
||||
/// The object that responds to messages from the other end.
|
||||
///
|
||||
/// The object that responds to messages from the other end.
|
||||
///
|
||||
@property(retain) id exportedObject;
|
||||
|
||||
/// A block to run when the connection is invalidated.
|
||||
///
|
||||
/// A block to run when the connection is invalidated.
|
||||
///
|
||||
@property(copy) SNTXPCInvalidationBlock invalidationHandler;
|
||||
|
||||
/// A block to run when the connection has been accepted.
|
||||
///
|
||||
/// A block to run when the connection has been accepted.
|
||||
///
|
||||
@property(copy) SNTXPCAcceptedBlock acceptedHandler;
|
||||
|
||||
/// A block to run when the connection has been rejected.
|
||||
///
|
||||
/// A block to run when the connection has been rejected.
|
||||
///
|
||||
@property(copy) SNTXPCRejectedBlock rejectedHandler;
|
||||
|
||||
/// Initializer for the 'server' side of the connection, the binary that was started by launchd.
|
||||
///
|
||||
/// Initializer for the 'server' side of the connection, the binary that was started by launchd.
|
||||
///
|
||||
/// @param name MachService name
|
||||
///
|
||||
- (instancetype)initServerWithName:(NSString *)name;
|
||||
|
||||
/// Initializer for the 'client' side of the connection. If the 'server' was started as a
|
||||
/// LaunchDaemon (running as root), pass |NSXPCConnectionPrivileged| for |options|, otherwise use 0.
|
||||
///
|
||||
/// Initializer for the 'client' side of the connection.
|
||||
///
|
||||
/// @param name MachService name
|
||||
/// @param options Use NSXPCConnectionPrivileged if the server is running as root, otherwise use 0.
|
||||
///
|
||||
- (instancetype)initClientWithName:(NSString *)name options:(NSXPCConnectionOptions)options;
|
||||
|
||||
/// Call when the properties of the object have been set-up and you're ready for connections.
|
||||
///
|
||||
/// Call when the properties of the object have been set-up and you're ready for connections.
|
||||
/// Blocks the executing thread for up to 5s while waiting for the verification to complete.
|
||||
///
|
||||
- (void)resume;
|
||||
|
||||
///
|
||||
/// Invalidate the connection. This must be done before the connection can be released.
|
||||
///
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -21,14 +21,22 @@
|
||||
@end
|
||||
|
||||
@interface SNTXPCConnection ()
|
||||
|
||||
///
|
||||
/// The XPC listener (used on server-side only).
|
||||
///
|
||||
@property NSXPCListener *listenerObject;
|
||||
|
||||
///
|
||||
/// The current connection object.
|
||||
///
|
||||
@property NSXPCConnection *currentConnection;
|
||||
|
||||
///
|
||||
/// The remote interface to use while the connection hasn't been validated.
|
||||
///
|
||||
@property NSXPCInterface *validatorInterface;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SNTXPCConnection
|
||||
@@ -88,6 +96,7 @@
|
||||
|
||||
[connection resume];
|
||||
|
||||
__block BOOL verificationComplete = NO;
|
||||
[[connection remoteObjectProxy] isConnectionValidWithBlock:^void(BOOL response) {
|
||||
pid_t pid = self.currentConnection.processIdentifier;
|
||||
|
||||
@@ -101,12 +110,20 @@
|
||||
self.currentConnection.exportedObject = self.exportedObject;
|
||||
[self invokeAcceptedHandler];
|
||||
[self.currentConnection resume];
|
||||
verificationComplete = YES;
|
||||
} else {
|
||||
[self invokeRejectedHandler];
|
||||
[self.currentConnection invalidate];
|
||||
self.currentConnection = nil;
|
||||
verificationComplete = YES;
|
||||
}
|
||||
}];
|
||||
|
||||
// Wait for validation to complete, at most 5s
|
||||
for (int sleepLoops = 0; sleepLoops < 1000 && !verificationComplete; sleepLoops++) {
|
||||
usleep(5000);
|
||||
}
|
||||
if (!verificationComplete) [self invalidate];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,11 +169,11 @@
|
||||
|
||||
[self invokeAcceptedHandler];
|
||||
|
||||
// Let remote end know that we accepted. Note: in acception this must come last otherwise
|
||||
// Let remote end know that we accepted. In acception this must come last otherwise
|
||||
// the remote end might start sending messages before the interface is fully set-up.
|
||||
block(YES);
|
||||
} else {
|
||||
// Let remote end know that we rejected. Note: in rejection this must come first otherwise
|
||||
// Let remote end know that we rejected. In rejection this must come first otherwise
|
||||
// the connection is invalidated before the client ever realizes.
|
||||
block(NO);
|
||||
|
||||
@@ -194,4 +211,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Connection tear-down
|
||||
|
||||
- (void)invalidate {
|
||||
if (self.currentConnection) {
|
||||
[self.currentConnection invalidate];
|
||||
self.currentConnection = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -17,24 +17,32 @@
|
||||
@class SNTRule;
|
||||
@class SNTStoredEvent;
|
||||
|
||||
/// Protocol implemented by santad and utilized by santactl
|
||||
///
|
||||
/// Protocol implemented by santad and utilized by santactl
|
||||
///
|
||||
@protocol SNTDaemonControlXPC
|
||||
|
||||
/// Kernel ops
|
||||
///
|
||||
/// Kernel ops
|
||||
///
|
||||
- (void)cacheCount:(void (^)(uint64_t))reply;
|
||||
- (void)flushCache:(void (^)(BOOL))reply;
|
||||
|
||||
/// Database ops
|
||||
///
|
||||
/// 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)databaseEventCount:(void (^)(uint64_t count))reply;
|
||||
- (void)databaseEventForSHA1:(NSString *)sha1 withReply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 withReply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventsPending:(void (^)(NSArray *events))reply;
|
||||
- (void)databaseRemoveEventsWithIDs:(NSArray *)ids;
|
||||
|
||||
/// Misc ops
|
||||
///
|
||||
/// Misc ops
|
||||
///
|
||||
- (void)clientMode:(void (^)(santa_clientmode_t))reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode withReply:(void (^)())reply;
|
||||
|
||||
@@ -42,11 +50,15 @@
|
||||
|
||||
@interface SNTXPCControlInterface : NSObject
|
||||
|
||||
/// Returns the MachService ID for this service.
|
||||
///
|
||||
/// Returns the MachService ID for this service.
|
||||
///
|
||||
+ (NSString *)serviceId;
|
||||
|
||||
/// Returns an initialized NSXPCInterface for the SNTDaemonControlXPC protocol.
|
||||
/// Ensures any methods that accept custom classes as arguments are set-up before returning
|
||||
///
|
||||
/// Returns an initialized NSXPCInterface for the SNTDaemonControlXPC protocol.
|
||||
/// Ensures any methods that accept custom classes as arguments are set-up before returning
|
||||
///
|
||||
+ (NSXPCInterface *)controlInterface;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -13,18 +13,22 @@
|
||||
/// limitations under the License.
|
||||
|
||||
/// Protocol implemented by SantaNotifier and utilized by santad
|
||||
@class SNTNotificationMessage;
|
||||
@class SNTStoredEvent;
|
||||
@protocol SNTNotifierXPC
|
||||
- (void)postBlockNotification:(SNTNotificationMessage *)event;
|
||||
- (void)postBlockNotification:(SNTStoredEvent *)event withCustomMessage:(NSString *)message;
|
||||
@end
|
||||
|
||||
@interface SNTXPCNotifierInterface : NSObject
|
||||
|
||||
/// Returns the MachService ID for this service.
|
||||
///
|
||||
/// @return the MachService ID for this service.
|
||||
///
|
||||
+ (NSString *)serviceId;
|
||||
|
||||
/// Returns an initialized NSXPCInterface for the SNTNotifierXPC protocol.
|
||||
/// Ensures any methods that accept custom classes as arguments are set-up before returning
|
||||
///
|
||||
/// @return an initialized NSXPCInterface for the SNTNotifierXPC protocol.
|
||||
/// Ensures any methods that accept custom classes as arguments are set-up before returning
|
||||
///
|
||||
+ (NSXPCInterface *)notifierInterface;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -2,26 +2,22 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.santa-driver</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>KEXT</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Google, Inc.</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.7</string>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>IOKitPersonalities</key>
|
||||
<dict>
|
||||
<key>SantaDriver</key>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -19,63 +19,124 @@ OSDefineMetaClassAndStructors(SantaDecisionManager, OSObject);
|
||||
|
||||
#pragma mark Object Lifecycle
|
||||
|
||||
SantaDecisionManager *SantaDecisionManager::WithQueueAndPID(
|
||||
IOSharedDataQueue *queue, pid_t pid) {
|
||||
SantaDecisionManager *me = new SantaDecisionManager;
|
||||
bool SantaDecisionManager::init() {
|
||||
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());
|
||||
|
||||
if (me && !me->InitWithQueueAndPID(queue, pid)) {
|
||||
me->free();
|
||||
return NULL;
|
||||
}
|
||||
cached_decisions_ = OSDictionary::withCapacity(1000);
|
||||
|
||||
return me;
|
||||
}
|
||||
owning_pid_ = 0;
|
||||
|
||||
bool SantaDecisionManager::InitWithQueueAndPID(
|
||||
IOSharedDataQueue *queue, pid_t pid) {
|
||||
if (!super::init()) return false;
|
||||
|
||||
if (!pid) return false;
|
||||
if (!queue) return false;
|
||||
|
||||
listener_invocations_ = 0;
|
||||
dataqueue_ = queue;
|
||||
owning_pid_ = pid;
|
||||
owning_proc_ = proc_find(pid);
|
||||
|
||||
if (!(dataqueue_lock_ = IORWLockAlloc())) return FALSE;
|
||||
if (!(cached_decisions_lock_ = IORWLockAlloc())) return FALSE;
|
||||
if (!(cached_decisions_ = OSDictionary::withCapacity(1000))) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
void SantaDecisionManager::free() {
|
||||
proc_rele(owning_proc_);
|
||||
|
||||
if (cached_decisions_) {
|
||||
cached_decisions_->release();
|
||||
cached_decisions_ = NULL;
|
||||
}
|
||||
|
||||
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_);
|
||||
if (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();
|
||||
}
|
||||
|
||||
# pragma mark Cache Management
|
||||
#pragma mark Client Management
|
||||
|
||||
bool SantaDecisionManager::AddToCache(
|
||||
void SantaDecisionManager::ConnectClient(IOSharedDataQueue *queue, pid_t pid) {
|
||||
if (!pid) return;
|
||||
if (!queue) return;
|
||||
|
||||
// Any decisions made while the daemon wasn't
|
||||
// connected should be cleared
|
||||
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.
|
||||
santa_message_t message;
|
||||
message.action = ACTION_REQUEST_SHUTDOWN;
|
||||
message.userId = 0;
|
||||
message.pid = 0;
|
||||
message.ppid = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::ClientConnected() {
|
||||
return owning_pid_ > 0;
|
||||
}
|
||||
|
||||
# pragma mark Listener Control
|
||||
|
||||
kern_return_t SantaDecisionManager::StartListener() {
|
||||
vnode_listener_ = kauth_listen_scope(KAUTH_SCOPE_VNODE,
|
||||
vnode_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
if (!vnode_listener_) return kIOReturnInternalError;
|
||||
|
||||
LOGD("Vnode listener started.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
kern_return_t SantaDecisionManager::StopListener() {
|
||||
kauth_unlisten_scope(vnode_listener_);
|
||||
vnode_listener_ = NULL;
|
||||
|
||||
// Wait for any active invocations to finish before returning
|
||||
do {
|
||||
IOSleep(5);
|
||||
} while (listener_invocations_);
|
||||
|
||||
// Delete any cached decisions
|
||||
ClearCache();
|
||||
|
||||
LOGD("Vnode listener stopped.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
#pragma mark Cache Management
|
||||
|
||||
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
|
||||
@@ -87,35 +148,31 @@ bool SantaDecisionManager::AddToCache(
|
||||
cached_decisions_->flushCollection();
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (decision == ACTION_REQUEST_CHECKBW) {
|
||||
SantaMessage *pending = new SantaMessage();
|
||||
pending->setAction(ACTION_REQUEST_CHECKBW, 0);
|
||||
result = cached_decisions_->setObject(identifier, pending);
|
||||
cached_decisions_->setObject(identifier, pending);
|
||||
pending->release(); // it was retained when added to the dictionary
|
||||
} else {
|
||||
SantaMessage *pending = OSDynamicCast(
|
||||
SantaMessage, cached_decisions_->getObject(identifier));
|
||||
if (pending) {
|
||||
pending->setAction(decision, microsecs);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
IORWLockUnlock(cached_decisions_lock_);
|
||||
|
||||
return result;
|
||||
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_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,26 +181,25 @@ 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 (result == ACTION_RESPOND_CHECKBW_ALLOW ||
|
||||
result == ACTION_RESPOND_CHECKBW_DENY) {
|
||||
if (CHECKBW_RESPONSE_VALID(result)) {
|
||||
uint64_t diff_time = GetCurrentUptime();
|
||||
|
||||
if (result == ACTION_RESPOND_CHECKBW_ALLOW) {
|
||||
@@ -161,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;
|
||||
}
|
||||
}
|
||||
@@ -174,9 +230,12 @@ santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
# pragma mark Queue Management
|
||||
|
||||
bool SantaDecisionManager::PostToQueue(santa_message_t message) {
|
||||
IORWLockWrite(dataqueue_lock_);
|
||||
bool kr = dataqueue_->enqueue(&message, sizeof(message));
|
||||
IORWLockUnlock(dataqueue_lock_);
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
bool kr = false;
|
||||
if (dataqueue_) {
|
||||
kr = dataqueue_->enqueue(&message, sizeof(message));
|
||||
}
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
return kr;
|
||||
}
|
||||
|
||||
@@ -195,21 +254,10 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
|
||||
// If item wasn't in cache, fetch decision from daemon.
|
||||
if (return_action == ACTION_UNSET) {
|
||||
if (!CHECKBW_RESPONSE_VALID(return_action)) {
|
||||
// Add pending request to cache
|
||||
AddToCache(vnode_id_str, ACTION_REQUEST_CHECKBW, 0);
|
||||
|
||||
// Get SHA-1
|
||||
// TODO(rah): Investigate possible race condition where file is modified
|
||||
// in between SHA-1 being calculated and response for said file being
|
||||
// received.
|
||||
char sha[MAX_SHA1_STRING];
|
||||
if (!CalculateSHA1ForVnode(credential, vfs_context, vnode, sha)) {
|
||||
LOGD("Unable to get SHA-1 for file, denying execution");
|
||||
CacheCheck(vnode_id_str);
|
||||
return ACTION_RESPOND_CHECKBW_DENY;
|
||||
}
|
||||
|
||||
// Get path
|
||||
char path[MAX_PATH_LEN];
|
||||
int name_len = MAX_PATH_LEN;
|
||||
@@ -217,12 +265,20 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
path[0] = '\0';
|
||||
}
|
||||
|
||||
if (!ClientConnected()) {
|
||||
LOGI("Execution request without daemon running: %s", path);
|
||||
AddToCache(vnode_id_str,
|
||||
ACTION_RESPOND_CHECKBW_ALLOW,
|
||||
GetCurrentUptime());
|
||||
return ACTION_RESPOND_CHECKBW_ALLOW;
|
||||
}
|
||||
|
||||
// Prepare to send message to daemon
|
||||
santa_message_t message;
|
||||
strncpy(message.sha1, sha, MAX_SHA1_STRING);
|
||||
strncpy(message.path, path, MAX_PATH_LEN);
|
||||
message.userId = kauth_cred_getuid(credential);
|
||||
message.pid = proc_selfpid();
|
||||
message.ppid = proc_selfppid();
|
||||
message.action = ACTION_REQUEST_CHECKBW;
|
||||
message.vnode_id = vnode_id;
|
||||
|
||||
@@ -230,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;
|
||||
@@ -240,11 +301,13 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
for (int i = 0; i < kMaxRequestLoops; ++i) {
|
||||
IOSleep(kRequestLoopSleepMilliseconds);
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
if (return_action != ACTION_REQUEST_CHECKBW) break;
|
||||
if (CHECKBW_RESPONSE_VALID(return_action)) break;
|
||||
}
|
||||
} while (return_action == ACTION_REQUEST_CHECKBW && proc_exiting(owning_proc_) == 0);
|
||||
} while (!CHECKBW_RESPONSE_VALID(return_action) &&
|
||||
proc_exiting(owning_proc_) == 0);
|
||||
|
||||
if (return_action == ACTION_UNSET || return_action == ACTION_ERROR) {
|
||||
// If response is still not valid, the daemon exited
|
||||
if (!CHECKBW_RESPONSE_VALID(return_action)) {
|
||||
LOGE("Daemon process did not respond correctly. Allowing executions "
|
||||
"until it comes back.");
|
||||
CacheCheck(vnode_id_str);
|
||||
@@ -257,67 +320,6 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
|
||||
# pragma mark Misc
|
||||
|
||||
bool SantaDecisionManager::CalculateSHA1ForVnode(const kauth_cred_t credential,
|
||||
const vfs_context_t context,
|
||||
const vnode_t vp,
|
||||
char *out) {
|
||||
out[0] = '\0';
|
||||
|
||||
// Get binary size
|
||||
uint64_t binary_size;
|
||||
struct vnode_attr vap;
|
||||
VATTR_INIT(&vap);
|
||||
VATTR_WANTED(&vap, va_data_size);
|
||||
vnode_getattr(vp, &vap, context);
|
||||
binary_size = vap.va_data_size;
|
||||
|
||||
// Initialize the SHA1 context
|
||||
SHA1_CTX sha1_ctx;
|
||||
SHA1Init(&sha1_ctx);
|
||||
|
||||
// |chunkSize| should equal one page so that where possible
|
||||
// the kernel can offload the calculation to dedicated hardware.
|
||||
int chunkSize = PAGE_SIZE_64;
|
||||
void *readChunk = IOMalloc(chunkSize);
|
||||
|
||||
// Credentials needed for vn_rdwr
|
||||
kauth_cred_t kerncred = vfs_context_ucred(context);
|
||||
proc_t p = vfs_context_proc(context);
|
||||
|
||||
// Read the file in chunks, updating the SHA as we go
|
||||
for (uint64_t offset = 0; offset < binary_size; offset += chunkSize) {
|
||||
int readSize;
|
||||
if (offset + chunkSize > binary_size) {
|
||||
readSize = (int)(binary_size - offset);
|
||||
} else {
|
||||
readSize = chunkSize;
|
||||
}
|
||||
|
||||
int resid; // unused
|
||||
if (vn_rdwr(UIO_READ, vp, (caddr_t)readChunk, readSize, offset,
|
||||
UIO_SYSSPACE, IO_NOAUTH, kerncred, &resid, p) != 0) {
|
||||
IOFree(readChunk, chunkSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
SHA1Update(&sha1_ctx, readChunk, readSize);
|
||||
}
|
||||
|
||||
// Free |readChunk|
|
||||
IOFree(readChunk, chunkSize);
|
||||
|
||||
// Finalize the SHA-1 into |buf|
|
||||
char buf[MAX_SHA1_LEN];
|
||||
SHA1Final(buf, &sha1_ctx);
|
||||
|
||||
// Convert the binary SHA into a hex digest string
|
||||
for (int i = 0; i < MAX_SHA1_LEN; i++) {
|
||||
snprintf(out + (2*i), 3, "%02x", (unsigned char)buf[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t SantaDecisionManager::GetVnodeIDForVnode(const vfs_context_t context,
|
||||
const vnode_t vp) {
|
||||
struct vnode_attr vap;
|
||||
@@ -336,10 +338,6 @@ uint64_t SantaDecisionManager::GetCurrentUptime() {
|
||||
|
||||
# pragma mark Invocation Tracking & PID comparison
|
||||
|
||||
SInt32 SantaDecisionManager::GetListenerInvocations() {
|
||||
return listener_invocations_;
|
||||
}
|
||||
|
||||
void SantaDecisionManager::IncrementListenerInvocations() {
|
||||
OSIncrementAtomic(&listener_invocations_);
|
||||
}
|
||||
@@ -348,90 +346,13 @@ void SantaDecisionManager::DecrementListenerInvocations() {
|
||||
OSDecrementAtomic(&listener_invocations_);
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::MatchesOwningPID(const pid_t other_pid) {
|
||||
return (owning_pid_ == other_pid);
|
||||
}
|
||||
|
||||
# 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));
|
||||
if (!vnode_listener_) return kIOReturnInternalError;
|
||||
|
||||
LOGD("Vnode listener started.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
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);
|
||||
} while (GetListenerInvocations());
|
||||
|
||||
// Delete any cached decisions
|
||||
ClearCache();
|
||||
|
||||
LOGD("Vnode listener stopped.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
#undef super
|
||||
|
||||
#pragma mark Kauth Callbacks
|
||||
#pragma mark Kauth Callback
|
||||
|
||||
extern 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;
|
||||
}
|
||||
|
||||
|
||||
extern 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) {
|
||||
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 default action is to defer
|
||||
int returnResult = KAUTH_RESULT_DEFER;
|
||||
|
||||
@@ -449,16 +370,20 @@ extern int vnode_scope_callback(kauth_cred_t credential,
|
||||
vtype vt = vnode_vtype(vnode);
|
||||
if (vt != VREG) return returnResult;
|
||||
|
||||
// Don't operate on ACCESS events, as they're advisory
|
||||
if (action & KAUTH_VNODE_ACCESS) return returnResult;
|
||||
|
||||
// Filter for only WRITE_DATA actions
|
||||
if (action & KAUTH_VNODE_WRITE_DATA || action & KAUTH_VNODE_APPEND_DATA) {
|
||||
// Filter for only writes
|
||||
if (action & KAUTH_VNODE_WRITE_DATA ||
|
||||
action & KAUTH_VNODE_APPEND_DATA ||
|
||||
action & KAUTH_VNODE_DELETE) {
|
||||
char vnode_id_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_id_str, MAX_VNODE_ID_STR, "%llu",
|
||||
sdm->GetVnodeIDForVnode(vfs_context, vnode));
|
||||
|
||||
// If an execution request is pending, deny write
|
||||
if (sdm->GetFromCache(vnode_id_str) == ACTION_REQUEST_CHECKBW) {
|
||||
LOGD("Denying write due to pending execution: %s", vnode_id_str);
|
||||
*(reinterpret_cast<int *>(arg3)) = EACCES;
|
||||
return KAUTH_RESULT_DENY;
|
||||
}
|
||||
@@ -488,17 +413,7 @@ extern int vnode_scope_callback(kauth_cred_t credential,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <IOKit/IOLib.h>
|
||||
#include <IOKit/IOSharedDataQueue.h>
|
||||
#include <libkern/c++/OSDictionary.h>
|
||||
#include <libkern/crypto/sha1.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
@@ -27,88 +26,128 @@
|
||||
#include "SNTKernelCommon.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
/// The maximum number of milliseconds a cached deny message should be
|
||||
/// considered valid.
|
||||
///
|
||||
/// The maximum number of milliseconds a cached deny message should be
|
||||
/// considered valid.
|
||||
///
|
||||
const uint64_t kMaxDenyCacheTimeMilliseconds = 500;
|
||||
|
||||
/// The maximum number of milliseconds a cached allow message should be
|
||||
/// considered valid.
|
||||
///
|
||||
/// The maximum number of milliseconds a cached allow message should be
|
||||
/// considered valid.
|
||||
///
|
||||
const uint64_t kMaxAllowCacheTimeMilliseconds = 1000 * 60 * 60 * 24;
|
||||
|
||||
/// While waiting for a response from the daemon, this is the number of
|
||||
/// milliseconds to sleep for before checking the cache for a response.
|
||||
///
|
||||
/// While waiting for a response from the daemon, this is the number of
|
||||
/// milliseconds to sleep for before checking the cache for a response.
|
||||
///
|
||||
const int kRequestLoopSleepMilliseconds = 10;
|
||||
|
||||
/// While waiting for a response from the daemon, this is the maximum number
|
||||
/// of loops to wait before sending the request again.
|
||||
///
|
||||
/// While waiting for a response from the daemon, this is the maximum number
|
||||
/// of loops to wait before sending the request again.
|
||||
///
|
||||
const int kMaxRequestLoops = 50;
|
||||
|
||||
/// Maximum number of entries in the in-kernel cache.
|
||||
///
|
||||
/// Maximum number of entries in the in-kernel cache.
|
||||
///
|
||||
const int kMaxCacheSize = 10000;
|
||||
|
||||
/// SantaDecisionManager is responsible for intercepting Vnode execute actions
|
||||
/// and responding to the request appropriately.
|
||||
///
|
||||
/// Documentation on the Kauth parts can be found here:
|
||||
/// https://developer.apple.com/library/mac/technotes/tn2127/_index.html
|
||||
/// 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.
|
||||
///
|
||||
/// Documentation on the Kauth parts can be found here:
|
||||
/// https://developer.apple.com/library/mac/technotes/tn2127/_index.html
|
||||
///
|
||||
class SantaDecisionManager : public OSObject {
|
||||
OSDeclareDefaultStructors(SantaDecisionManager);
|
||||
|
||||
public:
|
||||
// Convenience constructor
|
||||
// Queue remains owned by caller but must exist for lifetime of
|
||||
// SantaDecisionManager instance.
|
||||
static SantaDecisionManager *WithQueueAndPID(
|
||||
IOSharedDataQueue *queue, pid_t pid);
|
||||
/// Used for initialization after instantiation. Required because
|
||||
/// constructors cannot throw inside kernel-space.
|
||||
bool init();
|
||||
|
||||
bool InitWithQueueAndPID(IOSharedDataQueue *queue, pid_t pid);
|
||||
/// Called automatically when retain count drops to 0.
|
||||
void free();
|
||||
|
||||
// Decision Fetching / Daemon Communication
|
||||
/// Called by SantaDriverClient when a client connects, providing the data
|
||||
/// queue used to pass messages and the pid of the client process.
|
||||
void ConnectClient(IOSharedDataQueue *queue, pid_t pid);
|
||||
|
||||
/// Called by SantaDriverClient when a client disconnects
|
||||
void DisconnectClient();
|
||||
|
||||
/// Returns whether a client is currently connected or not.
|
||||
bool ClientConnected();
|
||||
|
||||
/// Starts the kauth listener.
|
||||
kern_return_t StartListener();
|
||||
|
||||
/// 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();
|
||||
|
||||
/// Adds a decision to the cache, with a timestamp.
|
||||
void AddToCache(const char *identifier,
|
||||
const santa_action_t decision,
|
||||
const uint64_t microsecs);
|
||||
|
||||
/// Checks to see if a given identifier is in the cache and removes it.
|
||||
void CacheCheck(const char *identifier);
|
||||
|
||||
/// Returns the number of entries in the cache.
|
||||
uint64_t CacheCount();
|
||||
|
||||
/// Clears the cache.
|
||||
void ClearCache();
|
||||
|
||||
/// Fetches a response from the cache, first checking to see if the
|
||||
/// entry has expired.
|
||||
santa_action_t GetFromCache(const char *identifier);
|
||||
|
||||
/// Posts the requested message to the client data queue, if there is one.
|
||||
/// Uses dataqueue_lock_ to ensure two threads don't try to write to the
|
||||
/// queue at the same time.
|
||||
bool PostToQueue(santa_message_t);
|
||||
|
||||
/// Fetches an execution decision for a file, first using the cache and then
|
||||
/// by sending a message to the daemon and waiting until a response arrives.
|
||||
/// If a daemon isn't connected, will allow execution and cache, logging
|
||||
/// the path to the executed file.
|
||||
santa_action_t FetchDecision(const kauth_cred_t credential,
|
||||
const vfs_context_t vfs_context,
|
||||
const vnode_t vnode);
|
||||
|
||||
// Hash calculation
|
||||
bool CalculateSHA1ForVnode(const kauth_cred_t credential,
|
||||
const vfs_context_t context,
|
||||
const vnode_t vnode,
|
||||
char *out);
|
||||
|
||||
// Vnode ID string
|
||||
/// Fetches the vnode_id for a given vnode.
|
||||
uint64_t GetVnodeIDForVnode(const vfs_context_t context, const vnode_t vp);
|
||||
|
||||
// Cache management
|
||||
bool AddToCache(const char *identifier,
|
||||
const santa_action_t decision,
|
||||
const uint64_t microsecs);
|
||||
void CacheCheck(const char *identifier);
|
||||
uint64_t CacheCount();
|
||||
void ClearCache();
|
||||
santa_action_t GetFromCache(const char *identifier);
|
||||
|
||||
// Listener invocation management
|
||||
SInt32 GetListenerInvocations();
|
||||
void IncrementListenerInvocations();
|
||||
void DecrementListenerInvocations();
|
||||
|
||||
// Owning PID comparison
|
||||
bool MatchesOwningPID(const pid_t other_pid);
|
||||
|
||||
// Returns the current system uptime in microseconds
|
||||
/// Returns the current system uptime in microseconds
|
||||
uint64_t GetCurrentUptime();
|
||||
|
||||
// Starting and stopping the listener
|
||||
kern_return_t StartListener();
|
||||
kern_return_t StopListener();
|
||||
/// Increments the count of active vnode callback's pending.
|
||||
void IncrementListenerInvocations();
|
||||
|
||||
/// Decrements the count of active vnode callback's pending.
|
||||
void DecrementListenerInvocations();
|
||||
|
||||
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_;
|
||||
|
||||
@@ -116,41 +155,20 @@ class SantaDecisionManager : public OSObject {
|
||||
proc_t owning_proc_;
|
||||
|
||||
kauth_listener_t vnode_listener_;
|
||||
kauth_listener_t process_listener_;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
/// The callback function for the Vnode scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested
|
||||
/// @param VFS context
|
||||
/// @param Vnode being operated on
|
||||
/// @param Parent Vnode. May be NULL.
|
||||
/// @param Pointer to an errno-style error.
|
||||
extern 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 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 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);
|
||||
} // extern C
|
||||
///
|
||||
/// The kauth callback function for the Vnode scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested
|
||||
/// @param VFS context
|
||||
/// @param Vnode being operated on
|
||||
/// @param Parent Vnode. May be NULL.
|
||||
/// @param Pointer to an errno-style error.
|
||||
///
|
||||
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);
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTADECISIONMANAGER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -23,6 +23,10 @@ OSDefineMetaClassAndStructors(com_google_SantaDriver, IOService);
|
||||
bool SantaDriver::start(IOService *provider) {
|
||||
if (!super::start(provider)) return false;
|
||||
|
||||
santaDecisionManager = new SantaDecisionManager;
|
||||
santaDecisionManager->init();
|
||||
santaDecisionManager->StartListener();
|
||||
|
||||
registerService();
|
||||
|
||||
LOGI("Loaded, version %s.", OSKextGetCurrentVersionString());
|
||||
@@ -31,7 +35,17 @@ bool SantaDriver::start(IOService *provider) {
|
||||
}
|
||||
|
||||
void SantaDriver::stop(IOService *provider) {
|
||||
santaDecisionManager->StopListener();
|
||||
santaDecisionManager->release();
|
||||
santaDecisionManager = NULL;
|
||||
|
||||
LOGI("Unloaded.");
|
||||
|
||||
super::stop(provider);
|
||||
}
|
||||
|
||||
SantaDecisionManager* SantaDriver::GetDecisionManager() {
|
||||
return santaDecisionManager;
|
||||
}
|
||||
|
||||
#undef super
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -21,13 +21,27 @@
|
||||
#include "SantaDecisionManager.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
/// The driver class, which provides just the start/stop functions.
|
||||
///
|
||||
/// The driver class, which provides the start/stop functions and holds
|
||||
/// the SantaDecisionManager instance which the connected client
|
||||
/// communicates with.
|
||||
///
|
||||
class com_google_SantaDriver : public IOService {
|
||||
OSDeclareDefaultStructors(com_google_SantaDriver);
|
||||
|
||||
public:
|
||||
/// Called by the kernel when the kext is loaded
|
||||
bool start(IOService *provider);
|
||||
|
||||
/// Called by the kernel when the kext is unloaded
|
||||
void stop(IOService *provider);
|
||||
|
||||
/// Returns a pointer to the SantaDecisionManager created in start().
|
||||
SantaDecisionManager* GetDecisionManager();
|
||||
|
||||
private:
|
||||
SantaDecisionManager *santaDecisionManager;
|
||||
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTADRIVER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -20,7 +20,7 @@
|
||||
// The defines above can'be used in this function, must use the full names.
|
||||
OSDefineMetaClassAndStructors(com_google_SantaDriverClient, IOUserClient);
|
||||
|
||||
# pragma mark Driver Management
|
||||
#pragma mark Driver Management
|
||||
|
||||
bool SantaDriverClient::initWithTask(
|
||||
task_t owningTask, void *securityID, UInt32 type) {
|
||||
@@ -41,51 +41,39 @@ bool SantaDriverClient::start(IOService *provider) {
|
||||
if (!fProvider) return false;
|
||||
if (!super::start(provider)) return false;
|
||||
|
||||
fSDMLock = IOLockAlloc();
|
||||
fSDM = fProvider->GetDecisionManager();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SantaDriverClient::stop(IOService *provider) {
|
||||
super::stop(provider);
|
||||
|
||||
fProvider = NULL;
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::clientClose() {
|
||||
close();
|
||||
terminate(kIOServiceSynchronous);
|
||||
|
||||
fProvider = NULL;
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
bool SantaDriverClient::terminate(IOOptionBits options) {
|
||||
// We have to lock before this check in case the client exits and the kext
|
||||
// is unloaded very shortly afterwards.
|
||||
IOLockLock(fSDMLock);
|
||||
if (fSDM) {
|
||||
fSDM->StopListener();
|
||||
fSDM->DisconnectClient();
|
||||
LOGI("Client disconnected.");
|
||||
|
||||
// Ask santad to shutdown
|
||||
santa_message_t message;
|
||||
message.action = ACTION_REQUEST_SHUTDOWN;
|
||||
message.userId = 0;
|
||||
message.pid = 0;
|
||||
message.vnode_id = 0;
|
||||
fSDM->PostToQueue(message);
|
||||
fSharedMemory->release();
|
||||
fSharedMemory = NULL;
|
||||
|
||||
LOGI("Client disconnected.");
|
||||
|
||||
fSDM->release();
|
||||
fSDM = NULL;
|
||||
}
|
||||
IOLockUnlock(fSDMLock);
|
||||
fDataQueue->release();
|
||||
fDataQueue = NULL;
|
||||
|
||||
if (fProvider && fProvider->isOpen(this)) fProvider->close(this);
|
||||
|
||||
return super::terminate(options);
|
||||
}
|
||||
|
||||
#pragma mark Fetching memory and data queue notifications
|
||||
|
||||
IOReturn SantaDriverClient::registerNotificationPort(mach_port_t port,
|
||||
UInt32 type,
|
||||
UInt32 ref) {
|
||||
@@ -107,7 +95,10 @@ IOReturn SantaDriverClient::clientMemoryForType(UInt32 type,
|
||||
fSharedMemory->retain(); // client will decrement this ref
|
||||
*memory = fSharedMemory;
|
||||
|
||||
return fSDM->StartListener();
|
||||
fSDM->ConnectClient(fDataQueue, proc_selfpid());
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
return kIOReturnNoMemory;
|
||||
@@ -135,12 +126,6 @@ IOReturn SantaDriverClient::open() {
|
||||
return kIOReturnVMError;
|
||||
}
|
||||
|
||||
IOLockLock(fSDMLock);
|
||||
fSDM = SantaDecisionManager::WithQueueAndPID(fDataQueue, proc_selfpid());
|
||||
IOLockUnlock(fSDMLock);
|
||||
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -152,21 +137,6 @@ IOReturn SantaDriverClient::static_open(
|
||||
return target->open();
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::close() {
|
||||
if (!fProvider) return kIOReturnNotAttached;
|
||||
if (fProvider->isOpen(this)) fProvider->close(this);
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::static_close(
|
||||
SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments) {
|
||||
if (!target) return kIOReturnBadArgument;
|
||||
return target->close();
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::allow_binary(const uint64_t vnode_id) {
|
||||
char vnode_id_str[21];
|
||||
snprintf(vnode_id_str, sizeof(vnode_id_str), "%llu", vnode_id);
|
||||
@@ -239,8 +209,8 @@ IOReturn SantaDriverClient::externalMethod(
|
||||
IOExternalMethodDispatch *dispatch,
|
||||
OSObject *target,
|
||||
void *reference) {
|
||||
// Array of methods callable by clients. The order of these must match the
|
||||
// order of the items in |SantaDriverMethods| in SNTKernelCommon.h
|
||||
/// Array of methods callable by clients. The order of these must match the
|
||||
/// order of the items in SantaDriverMethods in SNTKernelCommon.h
|
||||
IOExternalMethodDispatch sMethods[kSantaUserClientNMethods] = {
|
||||
{
|
||||
reinterpret_cast<IOExternalMethodAction>(&SantaDriverClient::static_open),
|
||||
@@ -249,14 +219,6 @@ IOReturn SantaDriverClient::externalMethod(
|
||||
0, // output scalar
|
||||
0 // output struct
|
||||
},
|
||||
{
|
||||
reinterpret_cast<IOExternalMethodAction>(
|
||||
&SantaDriverClient::static_close),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
reinterpret_cast<IOExternalMethodAction>(
|
||||
&SantaDriverClient::static_allow_binary),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <IOKit/IOSharedDataQueue.h>
|
||||
#include <IOKit/IOLib.h>
|
||||
#include <IOKit/IODataQueueShared.h>
|
||||
#include <libkern/crypto/sha1.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/proc.h>
|
||||
@@ -30,83 +29,99 @@
|
||||
#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
|
||||
/// connect to the driver. Starting, stopping, handling connections, allocating
|
||||
/// shared memory and establishing a data queue is handled here.
|
||||
///
|
||||
/// Documentation on how the IOUserClient parts of this code work can be found
|
||||
/// here:
|
||||
/// @link https://developer.apple.com/library/mac/samplecode/SimpleUserClient/Listings/User_Client_Info_txt.html
|
||||
/// This class is instantiated by IOKit when a new client process attempts to
|
||||
/// connect to the driver. Starting, stopping, handling connections, allocating
|
||||
/// shared memory and establishing a data queue is handled here.
|
||||
///
|
||||
/// Documentation on how the IOUserClient parts of this code work can be found
|
||||
/// here:
|
||||
/// https://developer.apple.com/library/mac/samplecode/SimpleUserClient/Listings/User_Client_Info_txt.html
|
||||
///
|
||||
class com_google_SantaDriverClient : public IOUserClient {
|
||||
OSDeclareDefaultStructors(com_google_SantaDriverClient);
|
||||
|
||||
private:
|
||||
IOSharedDataQueue *fDataQueue;
|
||||
IOMemoryDescriptor *fSharedMemory;
|
||||
com_google_SantaDriver *fProvider;
|
||||
SantaDecisionManager *fSDM;
|
||||
IOLock *fSDMLock;
|
||||
|
||||
public:
|
||||
bool start(IOService *provider);
|
||||
void stop(IOService *provider);
|
||||
IOReturn clientClose();
|
||||
bool terminate(IOOptionBits options);
|
||||
/// Called as part of IOServiceOpen in clients
|
||||
bool initWithTask(task_t owningTask, void *securityID, UInt32 type);
|
||||
|
||||
/// Called after initWithTask as part of IOServiceOpen
|
||||
bool start(IOService *provider);
|
||||
|
||||
/// Called when this class is stopping
|
||||
void stop(IOService *provider);
|
||||
|
||||
/// Called when a client disconnects
|
||||
IOReturn clientClose();
|
||||
|
||||
/// Called when the driver is shutting down
|
||||
bool terminate(IOOptionBits options);
|
||||
|
||||
/// Called in clients with IOConnectSetNotificationPort
|
||||
IOReturn registerNotificationPort(
|
||||
mach_port_t port, UInt32 type, UInt32 refCon);
|
||||
|
||||
/// Called in clients with IOConnectMapMemory
|
||||
IOReturn clientMemoryForType(
|
||||
UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory);
|
||||
|
||||
/// Called in clients with IOConnectCallScalarMethod etc. Dispatches
|
||||
/// to the requested selector using the SantaDriverMethods enum in
|
||||
/// SNTKernelCommon.
|
||||
IOReturn externalMethod(
|
||||
UInt32 selector,
|
||||
IOExternalMethodArguments *arguments,
|
||||
IOExternalMethodDispatch *dispatch,
|
||||
OSObject *target, void *reference);
|
||||
|
||||
///
|
||||
/// The userpsace callable methods are below. Each method corresponds
|
||||
/// to an entry in SantaDriverMethods. Each method has a static version
|
||||
/// which just calls the method on the provided target.
|
||||
///
|
||||
|
||||
/// Called during client connection
|
||||
IOReturn open();
|
||||
static IOReturn static_open(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
IOReturn close();
|
||||
static IOReturn static_close(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
/// The daemon calls this to allow a binary.
|
||||
/// The daemon calls this to allow a binary.
|
||||
IOReturn allow_binary(uint64_t vnode_id);
|
||||
static IOReturn static_allow_binary(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
/// The daemon calls this to deny a binary.
|
||||
/// The daemon calls this to deny a binary.
|
||||
IOReturn deny_binary(uint64_t vnode_id);
|
||||
static IOReturn static_deny_binary(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
/// The daemon calls this to empty the cache.
|
||||
/// The daemon calls this to empty the cache.
|
||||
IOReturn clear_cache();
|
||||
static IOReturn static_clear_cache(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
/// The daemon calls this to find out how many items are in the cache
|
||||
/// The daemon calls this to find out how many items are in the cache
|
||||
IOReturn cache_count(uint64_t *output);
|
||||
static IOReturn static_cache_count(
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -19,15 +19,13 @@
|
||||
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
/// An OSObject wrapper around a @c santa_action_t and a time.
|
||||
/// Only OSObject subclasses can be inserted into an OSDictionary.
|
||||
///
|
||||
/// An OSObject wrapper around a @c santa_action_t and a time.
|
||||
/// Only OSObject subclasses can be inserted into an OSDictionary.
|
||||
///
|
||||
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;
|
||||
@@ -37,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
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.santactl</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Google, Inc.</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.7</string>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>CSFlags</key>
|
||||
<string>kill</string>
|
||||
</dict>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,63 +14,85 @@
|
||||
|
||||
@class SNTXPCConnection;
|
||||
|
||||
/// Protocol that each command must adhere to.
|
||||
///
|
||||
/// Protocol that each command must adhere to.
|
||||
///
|
||||
@protocol SNTCommand <NSObject>
|
||||
/// Return YES if command requires root.
|
||||
|
||||
///
|
||||
/// @return YES if command requires root.
|
||||
///
|
||||
+ (BOOL)requiresRoot;
|
||||
|
||||
/// A small summary of the command, to be printed with the list of available commands
|
||||
///
|
||||
/// @return YES if command requires connection to santad.
|
||||
///
|
||||
+ (BOOL)requiresDaemonConn;
|
||||
|
||||
///
|
||||
/// A small summary of the command, to be printed with the list of available commands
|
||||
///
|
||||
+ (NSString *)shortHelpText;
|
||||
|
||||
/// A longer description of the command when the user runs "santactl help x"
|
||||
///
|
||||
/// A longer description of the command when the user runs <tt>santactl help x</tt>
|
||||
///
|
||||
+ (NSString *)longHelpText;
|
||||
|
||||
@optional
|
||||
|
||||
/// Either of the following two methods needs to be implemented
|
||||
|
||||
/// Called when the user is running the command
|
||||
/// @param arguments an array of arguments passed in
|
||||
/// @note This method (or one of the methods it calls) is responsible for calling exit().
|
||||
+ (void)runWithArguments:(NSArray *)arguments;
|
||||
|
||||
/// Called when the user is running the command
|
||||
/// @param arguments an array of arguments passed in
|
||||
/// @param connection to santad. Will be nil if connection failed.
|
||||
/// @note This method (or one of the methods it calls) is responsible for calling exit().
|
||||
///
|
||||
/// Called when the user is running the command
|
||||
/// @param arguments an array of arguments passed in
|
||||
/// @param daemonConn connection to santad. Will be nil if connection failed or
|
||||
/// if @c requiresDaemonConn is @c NO
|
||||
///
|
||||
/// @note This method (or one of the methods it calls) is responsible for calling exit().
|
||||
///
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn;
|
||||
@end
|
||||
|
||||
/// Responsible for maintaining the list of available commands by name, printing their help text
|
||||
/// when requested and launching them when requested. All of the methods in this class are
|
||||
/// class methods because the @c registerCommand:named: method is called by the @c +load method
|
||||
/// of each command class and so we cannot rely on its instantiation.
|
||||
///
|
||||
/// Responsible for maintaining the list of available commands by name, printing their help text
|
||||
/// when requested and launching them when requested. All of the methods in this class are
|
||||
/// class methods because the @c registerCommand:named: method is called by the @c +load method
|
||||
/// of each command class and so we cannot rely on its instantiation.
|
||||
///
|
||||
@interface SNTCommandController : NSObject
|
||||
|
||||
/// Register a new command with the specified name. Do not use this directly, use the
|
||||
/// @c REGISTER_COMMAND_NAME macro instead.
|
||||
///
|
||||
/// Register a new command with the specified name. Do not use this directly, use the
|
||||
/// @c REGISTER_COMMAND_NAME macro instead.
|
||||
///
|
||||
+ (void)registerCommand:(Class<SNTCommand>)command named:(NSString *)name;
|
||||
|
||||
/// Returns a usage string listing all of the available commands
|
||||
///
|
||||
/// @return a usage string listing all of the available commands
|
||||
///
|
||||
+ (NSString *)usage;
|
||||
|
||||
/// Returns the descriptive text for the given command, if it exists
|
||||
///
|
||||
/// @return the descriptive text for the given command, if it exists
|
||||
///
|
||||
+ (NSString *)helpForCommandWithName:(NSString *)command;
|
||||
|
||||
|
||||
/// Returns YES if @c commandName exists.
|
||||
///
|
||||
/// @return YES if @c commandName exists.
|
||||
///
|
||||
+ (BOOL)hasCommandWithName:(NSString *)commandName;
|
||||
|
||||
/// Runs the given command with the given arguments.
|
||||
/// @c commandName the name of a previously-registered command
|
||||
/// @c arguments an array of arguments to pass to the command
|
||||
/// @return an integer return code to exit with.
|
||||
+ (int)runCommandWithName:(NSString *)commandName arguments:(NSArray *)arguments;
|
||||
///
|
||||
/// Runs the given command with the given arguments.
|
||||
///
|
||||
/// @param commandName the name of a previously-registered command
|
||||
/// @param arguments an array of arguments to pass to the command
|
||||
///
|
||||
+ (void)runCommandWithName:(NSString *)commandName arguments:(NSArray *)arguments;
|
||||
|
||||
@end
|
||||
|
||||
/// This macro registers a given class as a command with the name passed in @c a (which must be an
|
||||
/// NSString). Must be placed just inside the implementation of the class, ideally at the top.
|
||||
/// The class that uses this macro must implement the SNTCommand protcol.
|
||||
///
|
||||
/// This macro registers a given class as a command with the name passed in @c a (which must be an
|
||||
/// NSString). Must be placed just inside the implementation of the class, ideally at the top.
|
||||
/// The class that uses this macro must implement the @c SNTCommand protcol.
|
||||
///
|
||||
#define REGISTER_COMMAND_NAME(a) \
|
||||
+ (void)load { [SNTCommandController registerCommand:[self class] named:a]; }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -48,85 +48,64 @@ static NSMutableDictionary *registeredCommands;
|
||||
[cmdName UTF8String], [cmd shortHelpText]];
|
||||
}
|
||||
|
||||
[helpText appendFormat:@"\nSee 'santactl help <command>' to read about a specific subcommand."];
|
||||
return helpText;
|
||||
}
|
||||
|
||||
+ (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];
|
||||
daemonConn.remoteInterface = [SNTXPCControlInterface controlInterface];
|
||||
|
||||
__block int connected = -1;
|
||||
daemonConn.acceptedHandler = ^{
|
||||
connected = 1;
|
||||
};
|
||||
|
||||
daemonConn.rejectedHandler = ^{
|
||||
connected = 0;
|
||||
printf("The daemon rejected the connection\n");
|
||||
exit(1);
|
||||
};
|
||||
|
||||
daemonConn.invalidationHandler = ^{
|
||||
connected = 0;
|
||||
printf("An error occurred communicating with the daemon\n");
|
||||
printf("An error occurred communicating with the daemon, is it running?\n");
|
||||
exit(1);
|
||||
};
|
||||
|
||||
[daemonConn resume];
|
||||
|
||||
int idx = 10;
|
||||
do {
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
--idx;
|
||||
} while (connected == -1 && idx > 0);
|
||||
|
||||
if (connected > 0) {
|
||||
return daemonConn;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
return daemonConn;
|
||||
}
|
||||
|
||||
+ (BOOL)hasCommandWithName:(NSString *)commandName {
|
||||
return ([registeredCommands objectForKey:commandName] != nil);
|
||||
}
|
||||
|
||||
+ (int)runCommandWithName:(NSString *)commandName arguments:(NSArray *)arguments {
|
||||
+ (void)runCommandWithName:(NSString *)commandName arguments:(NSArray *)arguments {
|
||||
Class<SNTCommand> command = registeredCommands[commandName];
|
||||
if (command) {
|
||||
if ([command requiresRoot] && getuid() != 0) {
|
||||
printf("The command '%s' requires root privileges.\n", [commandName UTF8String]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ([(id)command respondsToSelector:@selector(runWithArguments:daemonConnection:)]) {
|
||||
[command runWithArguments:arguments daemonConnection:[self connectToDaemon]];
|
||||
} else if ([(id)command respondsToSelector:@selector(runWithArguments:)]) {
|
||||
[command runWithArguments:arguments];
|
||||
} else {
|
||||
printf("The command '%s' has not been implemented correctly.\n", [commandName UTF8String]);
|
||||
}
|
||||
|
||||
// The command is responsible for quitting.
|
||||
[[NSRunLoop mainRunLoop] run];
|
||||
if ([command requiresRoot] && getuid() != 0) {
|
||||
printf("The command '%s' requires root privileges.\n", [commandName UTF8String]);
|
||||
exit(2);
|
||||
}
|
||||
return 128;
|
||||
|
||||
SNTXPCConnection *daemonConn;
|
||||
if ([command requiresDaemonConn]) {
|
||||
daemonConn = [self connectToDaemon];
|
||||
}
|
||||
|
||||
[command runWithArguments:arguments daemonConnection:daemonConn];
|
||||
|
||||
// The command is responsible for quitting.
|
||||
[[NSRunLoop mainRunLoop] run];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTBinaryInfo.h"
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCodesignChecker.h"
|
||||
#import "SNTFileInfo.h"
|
||||
|
||||
@interface SNTCommandBinaryInfo : NSObject<SNTCommand>
|
||||
@end
|
||||
@@ -31,73 +31,66 @@ REGISTER_COMMAND_NAME(@"binaryinfo");
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (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, 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 {
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
NSString *filePath = [arguments firstObject];
|
||||
|
||||
if (!filePath) {
|
||||
LOGI(@"Missing file path");
|
||||
printf("Missing file path\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
BOOL directory;
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&directory]) {
|
||||
LOGI(@"File does not exist");
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:filePath];
|
||||
if (!fileInfo) {
|
||||
printf("Invalid file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
LOGI(@"Not a regular file");
|
||||
exit(1);
|
||||
}
|
||||
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]);
|
||||
|
||||
// Convert to absolute, standardized path
|
||||
filePath = [filePath stringByStandardizingPath];
|
||||
if (![filePath isAbsolutePath]) {
|
||||
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
filePath = [cwd stringByAppendingPathComponent:filePath];
|
||||
}
|
||||
|
||||
LOGI(@"Info for file: %@", filePath);
|
||||
LOGI(@"-----------------------------------------------------------");
|
||||
|
||||
SNTBinaryInfo *ftd = [[SNTBinaryInfo alloc] initWithPath:filePath];
|
||||
|
||||
LOGI(@"%-20s: %@", "SHA-1", [ftd SHA1]);
|
||||
|
||||
NSArray *archs = [ftd architectures];
|
||||
NSArray *archs = [fileInfo architectures];
|
||||
if (archs) {
|
||||
LOGI(@"%-20s: %@ (%@)", "Type", [ftd machoType], [archs componentsJoinedByString:@", "]);
|
||||
printf("%-12s: %s (%s)\n", "Type",
|
||||
[[fileInfo machoType] UTF8String],
|
||||
[[archs componentsJoinedByString:@", "] UTF8String]);
|
||||
} else {
|
||||
LOGI(@"%-20s: %@", "Type", [ftd 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: %@", "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");
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -29,13 +29,17 @@ REGISTER_COMMAND_NAME(@"flushcache");
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
#import "SNTCommandController.h"
|
||||
|
||||
/**
|
||||
* santactl is a command-line utility for managing Santa.
|
||||
* As it can be used for a number of distinct operations, its operation is split into different
|
||||
* 'commands' which are expected to be the first argument to the binary. The main function below
|
||||
* is simply responsible for either passing control to the specified command or printing a useful
|
||||
* usage string.
|
||||
**/
|
||||
///
|
||||
/// santactl is a command-line utility for managing Santa.
|
||||
/// As it can be used for a number of distinct operations, its operation is split into different
|
||||
/// 'commands' which are expected to be the first argument to the binary. The main function below
|
||||
/// is simply responsible for either passing control to the specified command or printing a useful
|
||||
/// usage string.
|
||||
///
|
||||
|
||||
void print_usage() {
|
||||
printf("Usage: santactl:\n%s\n", [[SNTCommandController usage] UTF8String]);
|
||||
@@ -75,6 +75,6 @@ int main(int argc, const char *argv[]) {
|
||||
return 128;
|
||||
}
|
||||
|
||||
return [SNTCommandController runCommandWithName:commandName arguments:arguments];
|
||||
[SNTCommandController runCommandWithName:commandName arguments:arguments];
|
||||
}
|
||||
}
|
||||
|
||||
165
Source/santactl/rule/SNTCommandRule.m
Normal file
165
Source/santactl/rule/SNTCommandRule.m
Normal file
@@ -0,0 +1,165 @@
|
||||
/// 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 "SNTLogging.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCodesignChecker.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTRule.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
|
||||
@interface SNTCommandRule : NSObject<SNTCommand>
|
||||
@property SNTXPCConnection *daemonConn;
|
||||
@end
|
||||
|
||||
@implementation SNTCommandRule
|
||||
|
||||
REGISTER_COMMAND_NAME(@"rule");
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Manually add/remove rules.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
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 {
|
||||
SNTConfigurator *config = [SNTConfigurator configurator];
|
||||
|
||||
// Ensure we have no privileges
|
||||
if (!DropRootPrivileges()) {
|
||||
printf("Failed to drop root privileges.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ([config syncBaseURL] != nil) {
|
||||
printf("SyncBaseURL is set, rules are managed centrally.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
NSString *action = [arguments firstObject];
|
||||
|
||||
// add or remove
|
||||
if (!action) {
|
||||
printf("Missing action - add or remove?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int state = RULESTATE_UNKNOWN;
|
||||
|
||||
if ([action compare:@"add" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
} else if ([action compare:@"remove" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_REMOVE;
|
||||
} else {
|
||||
printf("Unknown action, expected add or remove.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
NSString *customMsg = @"";
|
||||
NSString *SHA256 = nil;
|
||||
NSString *filePath = nil;
|
||||
|
||||
// parse arguments
|
||||
for (int i=1; i < [arguments count] ; i++ ) {
|
||||
NSString* argument = [arguments objectAtIndex:i];
|
||||
|
||||
if ([argument compare:@"--whitelist" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_WHITELIST;
|
||||
} else if ([argument compare:@"--blacklist" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_BLACKLIST;
|
||||
} else if ([argument compare:@"--silent-blacklist" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_SILENT_BLACKLIST;
|
||||
} else if ([argument compare:@"--message" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
printf("No message specified.\n");
|
||||
}
|
||||
|
||||
customMsg = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--path" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
printf("No path specified.\n");
|
||||
}
|
||||
|
||||
filePath = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--sha256" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > ([arguments count])) {
|
||||
printf("No SHA-256 specified.\n");
|
||||
}
|
||||
|
||||
SHA256 = [arguments objectAtIndex:i];
|
||||
} else {
|
||||
printf("Unknown argument %s.\n", [argument UTF8String]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == RULESTATE_UNKNOWN) {
|
||||
printf("No state specified.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (filePath) {
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:filePath];
|
||||
if (!fileInfo) {
|
||||
printf("Not a regular file or executable bundle.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SHA256 = [fileInfo SHA256];
|
||||
} else if (SHA256) {
|
||||
} else {
|
||||
printf("No SHA-256 or binary specified.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SNTRule *newRule = [[SNTRule alloc] init];
|
||||
newRule.shasum = SHA256;
|
||||
newRule.state = state;
|
||||
newRule.type = RULETYPE_BINARY;
|
||||
newRule.customMsg = customMsg;
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule withReply:^{
|
||||
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);
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,11 +14,6 @@
|
||||
|
||||
#import "SNTCommandController.h"
|
||||
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
|
||||
#import "SNTBinaryInfo.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@@ -33,25 +28,34 @@ REGISTER_COMMAND_NAME(@"status");
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (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
|
||||
__block uint64_t cacheCount = -1;
|
||||
@@ -59,9 +63,8 @@ REGISTER_COMMAND_NAME(@"status");
|
||||
cacheCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (cacheCount == -1);
|
||||
LOGI(@">>> Kernel Info");
|
||||
LOGI(@"%-30s | %d", "Kernel cache count", cacheCount);
|
||||
LOGI(@"");
|
||||
printf(">>> Kernel Info\n");
|
||||
printf(" %-25s | %lld\n", "Kernel cache count", cacheCount);
|
||||
|
||||
// Database counts
|
||||
__block uint64_t eventCount = 1, binaryRuleCount = -1, certRuleCount = -1;
|
||||
@@ -73,42 +76,13 @@ REGISTER_COMMAND_NAME(@"status");
|
||||
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(@"");
|
||||
|
||||
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"];
|
||||
}
|
||||
|
||||
SNTBinaryInfo *driverInfo =
|
||||
[[SNTBinaryInfo alloc] initWithPath:@"/System/Library/Extensions/santa-driver.kext"];
|
||||
if (driverInfo) {
|
||||
return [driverInfo.bundleVersion stringByAppendingString:@" (unloaded)"];
|
||||
}
|
||||
|
||||
return @"not found";
|
||||
}
|
||||
|
||||
+ (NSString *)daemonVersion {
|
||||
SNTBinaryInfo *daemonInfo = [[SNTBinaryInfo alloc] initWithPath:@"/usr/libexec/santad"];
|
||||
return daemonInfo.bundleVersion;
|
||||
}
|
||||
|
||||
+ (NSString *)guiVersion {
|
||||
SNTBinaryInfo *guiInfo =
|
||||
[[SNTBinaryInfo 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
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,40 +12,70 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// An authenticating NSURLSession, which can do both pinned verification of the SSL server
|
||||
/// and handle client certificate authentication from the keychain.
|
||||
///
|
||||
/// An authenticating NSURLSession, which can do both pinned verification of the SSL server
|
||||
/// and handle client certificate authentication from the keychain.
|
||||
///
|
||||
@interface SNTAuthenticatingURLSession : NSObject<NSURLSessionDelegate>
|
||||
|
||||
/// The underlying session. Pass this session to NSURLRequest methods.
|
||||
///
|
||||
/// The underlying session. Pass this session to NSURLRequest methods.
|
||||
///
|
||||
@property(readonly) NSURLSession *session;
|
||||
|
||||
/// If set, this is the user-agent to send with requests, otherwise remains the default
|
||||
/// CFNetwork-based name.
|
||||
///
|
||||
/// If set, this is the user-agent to send with requests, otherwise remains the default
|
||||
/// CFNetwork-based name.
|
||||
///
|
||||
@property(nonatomic) NSString *userAgent;
|
||||
|
||||
/// If set, the server that we connect to _must_ match this string. Redirects to other
|
||||
/// hosts will not be allowed.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
@property(nonatomic) NSString *serverHostname;
|
||||
|
||||
/// This should be PEM data containing one or more certificates to use to verify the server's
|
||||
/// certificate chain. This will override the trusted roots in the System Roots.
|
||||
///
|
||||
/// This should be PEM data containing one or more certificates to use to verify the server's
|
||||
/// certificate chain. This will override the trusted roots in the System Roots.
|
||||
///
|
||||
@property(nonatomic) NSData *serverRootsPemData;
|
||||
|
||||
/// If set and client certificate authentication is needed, will search the keychain for a
|
||||
/// certificate matching this common name and use that for authentication
|
||||
/// @note: Not case sensitive
|
||||
/// @note: If multiple matching certificates are found, the first one is used.
|
||||
/// @note: If this property is not set and neither is |clientCertIssuerCn|, the allowed issuers
|
||||
/// provided by the server will be used to find a matching certificate.
|
||||
///
|
||||
/// If set and client certificate authentication is needed, the pkcs#12 file will be loaded
|
||||
///
|
||||
@property(nonatomic) NSString *clientCertFile;
|
||||
|
||||
///
|
||||
/// If set and client certificate authentication is needed, the password being used for
|
||||
/// loading the clientCertFile
|
||||
///
|
||||
@property(nonatomic) NSString *clientCertPassword;
|
||||
|
||||
///
|
||||
/// If set and client certificate authentication is needed, will search the keychain for a
|
||||
/// certificate matching this common name and use that for authentication
|
||||
/// @note Not case sensitive
|
||||
/// @note If multiple matching certificates are found, the first one is used.
|
||||
/// @note If this property is not set and neither is |clientCertIssuerCn|, the allowed issuers
|
||||
/// provided by the server will be used to find a matching certificate.
|
||||
///
|
||||
@property(nonatomic) NSString *clientCertCommonName;
|
||||
|
||||
/// If set and client certificate authentication is needed, will search the keychain for a
|
||||
/// certificate issued by an issuer with this name and use that for authentication.
|
||||
///
|
||||
/// @note: Not case sensitive
|
||||
/// @note: If multiple matching certificates are found, the first one is used.
|
||||
/// @note: If this property is not set and neither is |clientCertCommonName|, the allowed issuers
|
||||
/// provided by the server will be used to find a matching certificate.
|
||||
/// If set and client certificate authentication is needed, will search the keychain for a
|
||||
/// certificate issued by an issuer with this name and use that for authentication.
|
||||
///
|
||||
/// @note Not case sensitive
|
||||
/// @note If multiple matching certificates are found, the first one is used.
|
||||
/// @note If this property is not set and neither is |clientCertCommonName|, the allowed issuers
|
||||
/// provided by the server will be used to find a matching certificate.
|
||||
///
|
||||
@property(nonatomic) NSString *clientCertIssuerCn;
|
||||
|
||||
/// Designated initializer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -15,7 +15,6 @@
|
||||
#import "SNTAuthenticatingURLSession.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDERDecoder.h"
|
||||
#import "SNTLogging.h"
|
||||
|
||||
@@ -69,25 +68,26 @@
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NSString *authMethod = [protectionSpace authenticationMethod];
|
||||
|
||||
if (authMethod == NSURLAuthenticationMethodClientCertificate && NO) {
|
||||
if (authMethod == NSURLAuthenticationMethodClientCertificate) {
|
||||
NSURLCredential *cred = [self clientCredentialForProtectionSpace:protectionSpace];
|
||||
if (cred) {
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
|
||||
return;
|
||||
} else {
|
||||
LOGE(@"Server asked for client authentication but no usable client certificate found.");
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
return;
|
||||
}
|
||||
@@ -97,6 +97,7 @@
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
|
||||
return;
|
||||
} else {
|
||||
LOGE(@"Unable to verify server identity.");
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
return;
|
||||
}
|
||||
@@ -105,106 +106,158 @@
|
||||
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
||||
}
|
||||
|
||||
#pragma mark Private Helpers for URLSession:didReceiveChallenge:completionHandler:
|
||||
|
||||
/// Handles the process of locating a valid client certificate for authentication.
|
||||
/// Operates in one of three modes, depending on the configuration in config.plist
|
||||
///
|
||||
/// Mode 1: if syncClientAuthCertificateCn is set, look for an identity in the keychain with a
|
||||
/// matching common name and return it.
|
||||
/// Mode 2: if syncClientAuthCertificateIssuer is set, look for an identity in the keychain with a
|
||||
/// matching issuer common name and return it.
|
||||
/// Mode 3: use the list of issuer details sent down by the server to find an identity in the
|
||||
/// keychain.
|
||||
///
|
||||
/// If a valid identity cannot be found, returns nil.
|
||||
- (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
|
||||
__block OSStatus err = errSecSuccess;
|
||||
CFArrayRef cfIdentities = NULL;
|
||||
err = SecItemCopyMatching((__bridge CFDictionaryRef)@{
|
||||
(id)kSecClass : (id)kSecClassIdentity,
|
||||
(id)kSecReturnRef : @YES,
|
||||
(id)kSecMatchLimit : (id)kSecMatchLimitAll }, (CFTypeRef *)&cfIdentities);
|
||||
|
||||
if (err != noErr) {
|
||||
LOGD(@"Client Trust: Failed to load client identities, SecItemCopyMatching returned: %d",
|
||||
(int)err);
|
||||
return nil;
|
||||
}
|
||||
NSArray *identities = CFBridgingRelease(cfIdentities);
|
||||
|
||||
__block SecIdentityRef _foundIdentity;
|
||||
|
||||
// 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;
|
||||
|
||||
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) {
|
||||
if ([clientCert.commonName compare:self.clientCertCommonName
|
||||
options:NSCaseInsensitiveSearch]) {
|
||||
LOGD(@"Client Trust: Valid client identity %@", clientCert);
|
||||
_foundIdentity = identityRef;
|
||||
CFRetain(_foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
} else if (self.clientCertIssuerCn) {
|
||||
if ([clientCert.issuerCommonName compare:self.clientCertIssuerCn
|
||||
options:NSCaseInsensitiveSearch]) {
|
||||
LOGD(@"Client Trust: Valid client identity %@", clientCert);
|
||||
_foundIdentity = identityRef;
|
||||
CFRetain(_foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||
newRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
||||
if (self.refusesRedirects) {
|
||||
completionHandler(NULL);
|
||||
} 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]) {
|
||||
LOGD(@"Client Trust: Valid client identity %@", clientCert);
|
||||
_foundIdentity = identityRef;
|
||||
CFRetain(_foundIdentity);
|
||||
*stop = YES;
|
||||
return; // return from enumeration block
|
||||
}
|
||||
}
|
||||
completionHandler(request);
|
||||
}
|
||||
}];
|
||||
|
||||
if (_foundIdentity == NULL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [NSURLCredential credentialWithIdentity:_foundIdentity
|
||||
certificates:nil
|
||||
persistence:NSURLCredentialPersistenceForSession];
|
||||
}
|
||||
|
||||
/// Handles the process of evaluating the server's certificate chain.
|
||||
/// Operates in one of three modes, depending on the configuration in config.plist
|
||||
#pragma mark Private Helpers for URLSession:didReceiveChallenge:completionHandler:
|
||||
|
||||
///
|
||||
/// Mode 1: if syncServerAuthRootsData is set, evaluates the server's certificate chain contains
|
||||
/// one of the certificates in the PEM data in the config plist.
|
||||
/// Mode 2: if syncServerAuthRootsFile is set, evaluates the server's certificate chain contains
|
||||
/// one of the certificates in the PEM data in the file specified.
|
||||
/// Mode 3: evaluates the server's certificate chain is trusted by the keychain.
|
||||
/// Handles the process of locating a valid client certificate for authentication.
|
||||
/// Operates in one of four modes, depending on the configuration in config.plist
|
||||
///
|
||||
/// Mode 1: if syncClientAuthCertificateFile is set, use the identity in the pkcs file
|
||||
/// Mode 2: if syncClientAuthCertificateCn is set, look for an identity in the keychain with a
|
||||
/// matching common name and return it.
|
||||
/// Mode 3: if syncClientAuthCertificateIssuer is set, look for an identity in the keychain with a
|
||||
/// matching issuer common name and return it.
|
||||
/// Mode 4: use the list of issuer details sent down by the server to find an identity in the
|
||||
/// keychain.
|
||||
///
|
||||
/// If a valid identity cannot be found, returns nil.
|
||||
///
|
||||
- (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
|
||||
__block OSStatus err = errSecSuccess;
|
||||
__block SecIdentityRef foundIdentity;
|
||||
|
||||
if (self.clientCertFile) {
|
||||
NSError *error;
|
||||
NSData *data = [NSData dataWithContentsOfFile:self.clientCertFile options:0 error:&error];
|
||||
if (error) {
|
||||
LOGD(@"Client Trust: Couldn't open client certificate %@: %@",
|
||||
self.clientCertFile,
|
||||
[error localizedDescription]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *options = (self.clientCertPassword ?
|
||||
@{(__bridge id)kSecImportExportPassphrase: self.clientCertPassword} :
|
||||
@{});
|
||||
|
||||
CFArrayRef cfIdentities;
|
||||
err = SecPKCS12Import(
|
||||
(__bridge CFDataRef)data, (__bridge CFDictionaryRef)options, &cfIdentities);
|
||||
NSArray *identities = CFBridgingRelease(cfIdentities);
|
||||
|
||||
if (err != errSecSuccess) {
|
||||
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)@{
|
||||
(id)kSecClass : (id)kSecClassIdentity,
|
||||
(id)kSecReturnRef : @YES,
|
||||
(id)kSecMatchLimit : (id)kSecMatchLimitAll }, (CFTypeRef *)&cfIdentities);
|
||||
|
||||
if (err != errSecSuccess) {
|
||||
LOGD(@"Client Trust: Failed to load client identities, SecItemCopyMatching returned: %d",
|
||||
(int)err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *identities = CFBridgingRelease(cfIdentities);
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Handles the process of evaluating the server's certificate chain.
|
||||
/// Operates in one of three modes, depending on the configuration in config.plist
|
||||
///
|
||||
/// Mode 1: if syncServerAuthRootsData is set, evaluates the server's certificate chain contains
|
||||
/// one of the certificates in the PEM data in the config plist.
|
||||
/// Mode 2: if syncServerAuthRootsFile is set, evaluates the server's certificate chain contains
|
||||
/// one of the certificates in the PEM data in the file specified.
|
||||
/// Mode 3: evaluates the server's certificate chain is trusted by the keychain.
|
||||
///
|
||||
/// If the server's certificate chain does not evaluate for any reason, returns nil.
|
||||
///
|
||||
/// If the server's certificate chain does not evaluate for any reason, returns nil.
|
||||
- (NSURLCredential *)serverCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
|
||||
SecTrustRef serverTrust = protectionSpace.serverTrust;
|
||||
if (serverTrust == NULL) {
|
||||
@@ -228,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");
|
||||
LOGD(@"Server Trust: Could not set anchor certificates: %d", err);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
@@ -237,7 +290,7 @@
|
||||
SecTrustResultType result = kSecTrustResultInvalid;
|
||||
err = SecTrustEvaluate(serverTrust, &result);
|
||||
if (err != errSecSuccess) {
|
||||
LOGE(@"Server Trust: Unable to evaluate certificate chain for server");
|
||||
LOGD(@"Server Trust: Unable to evaluate certificate chain for server: %d", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -251,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -24,7 +24,6 @@
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@@ -42,12 +41,16 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (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 {
|
||||
@@ -74,17 +77,32 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
if (santactlVersion) {
|
||||
authURLSession.userAgent = [authURLSession.userAgent stringByAppendingString:santactlVersion];
|
||||
}
|
||||
authURLSession.refusesRedirects = YES;
|
||||
|
||||
// Configure server auth
|
||||
if ([config syncServerAuthRootsFile]) {
|
||||
NSData *rootsData = [NSData dataWithContentsOfFile:[config syncServerAuthRootsFile]];
|
||||
NSError *error = nil;
|
||||
|
||||
NSData *rootsData = [NSData dataWithContentsOfFile:[config syncServerAuthRootsFile]
|
||||
options:0
|
||||
error:&error];
|
||||
authURLSession.serverRootsPemData = rootsData;
|
||||
|
||||
if (!rootsData) {
|
||||
LOGE(@"Couldn't open server root certificate file %@ with error: %@.",
|
||||
[config syncServerAuthRootsFile],
|
||||
[error localizedDescription]);
|
||||
exit(1);
|
||||
}
|
||||
} else if ([config syncServerAuthRootsData]) {
|
||||
authURLSession.serverRootsPemData = [config syncServerAuthRootsData];
|
||||
}
|
||||
|
||||
// Configure client auth
|
||||
if ([config syncClientAuthCertificateCn]) {
|
||||
if ([config syncClientAuthCertificateFile]) {
|
||||
authURLSession.clientCertFile = [config syncClientAuthCertificateFile];
|
||||
authURLSession.clientCertPassword = [config syncClientAuthCertificatePassword];
|
||||
} else if ([config syncClientAuthCertificateCn]) {
|
||||
authURLSession.clientCertCommonName = [config syncClientAuthCertificateCn];
|
||||
} else if ([config syncClientAuthCertificateIssuer]) {
|
||||
authURLSession.clientCertIssuerCn = [config syncClientAuthCertificateIssuer];
|
||||
@@ -100,18 +118,22 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
if (!s.progress.syncBaseURL) {
|
||||
LOGE(@"Missing SyncBaseURL. Can't sync without it.");
|
||||
exit(1);
|
||||
} else if (![s.progress.syncBaseURL.scheme isEqual:@"https"]) {
|
||||
LOGW(@"SyncBaseURL is not over HTTPS!");
|
||||
}
|
||||
authURLSession.serverHostname = s.progress.syncBaseURL.host;
|
||||
|
||||
s.progress.machineID = config.machineIDOverride;
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
s.progress.machineID = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
s.progress.machineID = config.machineID;
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
LOGE(@"Missing Machine ID. Can't sync without it.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s.progress.machineOwner = config.machineOwner;
|
||||
if (!s.progress.machineOwner) {
|
||||
s.progress.machineOwner = @"";
|
||||
LOGW(@"Missing Machine Owner.");
|
||||
}
|
||||
|
||||
if (arguments.count == 2 && [[arguments firstObject] isEqual:@"singleevent"]) {
|
||||
[s eventUploadSingleEvent:arguments[1]];
|
||||
@@ -125,18 +147,18 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Preflight complete");
|
||||
if (self.progress.uploadLogURL) {
|
||||
[self logUpload];
|
||||
} else {
|
||||
[self eventUpload];
|
||||
}
|
||||
} else {
|
||||
LOGE(@"Preflight failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Preflight complete");
|
||||
if (self.progress.uploadLogURL) {
|
||||
[self logUpload];
|
||||
} else {
|
||||
[self eventUpload];
|
||||
}
|
||||
} else {
|
||||
LOGE(@"Preflight failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)logUpload {
|
||||
@@ -144,14 +166,14 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Log upload complete");
|
||||
[self eventUpload];
|
||||
} else {
|
||||
LOGE(@"Log upload failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Log upload complete");
|
||||
[self eventUpload];
|
||||
} else {
|
||||
LOGE(@"Log upload failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)eventUpload {
|
||||
@@ -159,30 +181,30 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Event upload complete");
|
||||
[self ruleDownload];
|
||||
} else {
|
||||
LOGE(@"Event upload failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Event upload complete");
|
||||
[self ruleDownload];
|
||||
} else {
|
||||
LOGE(@"Event upload failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)eventUploadSingleEvent:(NSString *)sha1 {
|
||||
[SNTCommandSyncEventUpload uploadSingleEventWithSHA1:sha1
|
||||
session:self.session
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Event upload complete");
|
||||
exit(0);
|
||||
} else {
|
||||
LOGW(@"Event upload failed");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
- (void)eventUploadSingleEvent:(NSString *)sha256 {
|
||||
[SNTCommandSyncEventUpload uploadSingleEventWithSHA256:sha256
|
||||
session:self.session
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Event upload complete");
|
||||
exit(0);
|
||||
} else {
|
||||
LOGW(@"Event upload failed");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)ruleDownload {
|
||||
@@ -190,14 +212,14 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Rule download complete");
|
||||
[self postflight];
|
||||
} else {
|
||||
LOGE(@"Rule download failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Rule download complete");
|
||||
[self postflight];
|
||||
} else {
|
||||
LOGE(@"Rule download failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)postflight {
|
||||
@@ -205,15 +227,15 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
progress:self.progress
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Postflight complete");
|
||||
LOGI(@"Sync completed successfully");
|
||||
exit(0);
|
||||
} else {
|
||||
LOGE(@"Postflight failed");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Postflight complete");
|
||||
LOGI(@"Sync completed successfully");
|
||||
exit(0);
|
||||
} else {
|
||||
LOGE(@"Postflight failed");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
68
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
68
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/// 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 kBatchSize;
|
||||
extern NSString * const kUploadLogsURL;
|
||||
extern NSString * const kClientMode;
|
||||
extern NSString * const kClientModeMonitor;
|
||||
extern NSString * const kClientModeLockdown;
|
||||
|
||||
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 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;
|
||||
70
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
70
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
@@ -0,0 +1,70 @@
|
||||
/// 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_no";
|
||||
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 kBatchSize = @"batch_size";
|
||||
NSString * const kUploadLogsURL = @"upload_logs_url";
|
||||
NSString * const kClientMode = @"client_mode";
|
||||
NSString * const kClientModeMonitor = @"MONITOR";
|
||||
NSString * const kClientModeLockdown = @"LOCKDOWN";
|
||||
|
||||
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 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";
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -22,10 +22,10 @@
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
+ (void)uploadSingleEventWithSHA1:(NSString *)SHA1
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
@@ -27,7 +29,7 @@
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"eventupload/" stringByAppendingString:progress.machineID]
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseEventsPending:^(NSArray *events) {
|
||||
@@ -44,14 +46,14 @@
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)uploadSingleEventWithSHA1:(NSString *)SHA1
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"eventupload/" stringByAppendingString:progress.machineID]
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA1:SHA1 withReply:^(SNTStoredEvent *event) {
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA256:SHA256 withReply:^(SNTStoredEvent *event) {
|
||||
if (!event) {
|
||||
handler(YES);
|
||||
return;
|
||||
@@ -76,60 +78,35 @@
|
||||
|
||||
NSMutableArray *eventIds = [NSMutableArray arrayWithCapacity:events.count];
|
||||
for (SNTStoredEvent *event in events) {
|
||||
NSMutableDictionary *newEvent = [@{
|
||||
@"file_sha1": event.fileSHA1,
|
||||
@"file_path": [event.filePath stringByDeletingLastPathComponent],
|
||||
@"file_name": [event.filePath lastPathComponent],
|
||||
@"executing_user": event.executingUser,
|
||||
@"execution_time": @([event.occurrenceDate timeIntervalSince1970]),
|
||||
@"decision": @(event.decision),
|
||||
@"logged_in_users": event.loggedInUsers,
|
||||
@"current_sessions": event.currentSessions} mutableCopy];
|
||||
|
||||
|
||||
if (event.fileBundleID) newEvent[@"file_bundle_id"] = event.fileBundleID;
|
||||
if (event.fileBundleName) newEvent[@"file_bundle_name"] = event.fileBundleName;
|
||||
if (event.fileBundleVersion) newEvent[@"file_bundle_version"] = event.fileBundleVersion;
|
||||
if (event.fileBundleVersionString) {
|
||||
newEvent[@"file_bundle_version_string"] = event.fileBundleVersionString;
|
||||
}
|
||||
|
||||
if (event.certSHA1) newEvent[@"cert_sha1"] = event.certSHA1;
|
||||
if (event.certCN) newEvent[@"cert_cn"] = event.certCN;
|
||||
if (event.certOrg) newEvent[@"cert_org"] = event.certOrg;
|
||||
if (event.certOU) newEvent[@"cert_ou"] = event.certOU;
|
||||
if (event.certValidFromDate) {
|
||||
newEvent[@"cert_valid_from"] = @([event.certValidFromDate timeIntervalSince1970]);
|
||||
}
|
||||
if (event.certValidUntilDate) {
|
||||
newEvent[@"cert_valid_until"] = @([event.certValidUntilDate timeIntervalSince1970]);
|
||||
}
|
||||
|
||||
[uploadEvents addObject:newEvent];
|
||||
|
||||
[uploadEvents addObject:[self dictionaryForEvent:event]];
|
||||
[eventIds addObject:event.idx];
|
||||
|
||||
if (eventIds.count >= batchSize) break;
|
||||
}
|
||||
|
||||
NSDictionary *uploadReq = @{@"events": uploadEvents};
|
||||
NSDictionary *uploadReq = @{ kEvents: uploadEvents };
|
||||
|
||||
NSData *requestBody;
|
||||
@try {
|
||||
requestBody = [NSJSONSerialization dataWithJSONObject:uploadReq options:0 error:nil];
|
||||
} @catch (NSException *exception) {
|
||||
LOGE(@"Failed to parse event into JSON");
|
||||
LOGE(@"Failed to parse event(s) into JSON");
|
||||
LOGD(@"Parsing error: %@", [exception reason]);
|
||||
}
|
||||
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
[req setHTTPBody:requestBody];
|
||||
|
||||
[[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);
|
||||
@@ -138,7 +115,6 @@
|
||||
|
||||
NSArray *nextEvents = [events subarrayWithRange:NSMakeRange(eventIds.count,
|
||||
events.count - eventIds.count)];
|
||||
|
||||
if (nextEvents.count == 0) {
|
||||
handler(YES);
|
||||
} else {
|
||||
@@ -153,4 +129,45 @@
|
||||
}] resume];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryForEvent:(SNTStoredEvent *)event {
|
||||
#define ADDKEY(dict, key, value) if (value) dict[key] = value
|
||||
NSMutableDictionary *newEvent = [NSMutableDictionary dictionary];
|
||||
|
||||
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, kDecision, @(event.decision));
|
||||
ADDKEY(newEvent, kLoggedInUsers, event.loggedInUsers);
|
||||
ADDKEY(newEvent, kCurrentSessions, event.currentSessions);
|
||||
|
||||
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, 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[kSigningChain] = signingChain;
|
||||
|
||||
return newEvent;
|
||||
#undef ADDKEY
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,12 +14,14 @@
|
||||
|
||||
#import "SNTCommandSyncLogUpload.h"
|
||||
|
||||
#import "NSData+Zlib.h"
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
|
||||
|
||||
@implementation SNTCommandSyncLogUpload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
@@ -29,12 +31,50 @@
|
||||
NSURL *url = progress.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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
|
||||
@implementation SNTCommandSyncPostflight
|
||||
@@ -24,7 +25,7 @@
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"postflight/" stringByAppendingString:progress.machineID]
|
||||
NSURL *url = [NSURL URLWithString:[kURLPostflight stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
@@ -32,12 +33,15 @@
|
||||
[[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];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "SNTKernelCommon.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
@@ -28,22 +29,23 @@
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"preflight/" stringByAppendingString:progress.machineID]
|
||||
NSURL *url = [NSURL URLWithString:[kURLPreflight stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.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] = progress.machineOwner;
|
||||
|
||||
NSData *requestBody = [NSJSONSerialization dataWithJSONObject:requestDict
|
||||
options:0
|
||||
error:nil];
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
[req setHTTPBody:requestBody];
|
||||
|
||||
[[session dataTaskWithRequest:req completionHandler:^(NSData *data,
|
||||
@@ -51,17 +53,20 @@
|
||||
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"]];
|
||||
progress.eventBatchSize = [r[kBatchSize] intValue];
|
||||
progress.uploadLogURL = [NSURL URLWithString:r[kUploadLogsURL]];
|
||||
|
||||
if (r[@"client_mode"]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:[r[@"client_mode"] intValue] withReply:^{}];
|
||||
if (r[kClientMode] && [r[kClientMode] isEqual:kClientModeMonitor]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_MONITOR withReply:^{}];
|
||||
} else if (r[kClientMode] && [r[kClientMode] isEqual:kClientModeLockdown]) {
|
||||
[[daemonConn remoteObjectProxy] setClientMode:CLIENTMODE_LOCKDOWN withReply:^{}];
|
||||
}
|
||||
|
||||
handler(YES);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#import "SNTCommandSyncRuleDownload.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTRule.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
@@ -27,7 +28,7 @@
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"ruledownload/" stringByAppendingString:progress.machineID]
|
||||
NSURL *url = [NSURL URLWithString:[kURLRuleDownload stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
[self ruleDownloadWithCursor:nil
|
||||
url:url
|
||||
@@ -44,18 +45,18 @@
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
|
||||
NSDictionary *requestDict;
|
||||
if (cursor) {
|
||||
requestDict = @{@"cursor": cursor};
|
||||
} else {
|
||||
requestDict = @{};
|
||||
NSDictionary *requestDict = (cursor ? @{ kCursor: cursor } : @{});
|
||||
|
||||
if (!progress.downloadedRules) {
|
||||
progress.downloadedRules = [NSMutableArray array];
|
||||
}
|
||||
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPBody:[NSJSONSerialization dataWithJSONObject:requestDict
|
||||
options:0
|
||||
error:nil]];
|
||||
options:0
|
||||
error:nil]];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
[[session dataTaskWithRequest:req completionHandler:^(NSData *data,
|
||||
NSURLResponse *response,
|
||||
NSError *error) {
|
||||
@@ -64,48 +65,61 @@
|
||||
handler(NO);
|
||||
} else {
|
||||
NSDictionary *resp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
|
||||
NSArray *receivedRules = resp[@"rules"];
|
||||
|
||||
if (receivedRules.count == 0) {
|
||||
handler(YES);
|
||||
return;
|
||||
if (!resp) {
|
||||
LOGE(@"Failed to decode server's response");
|
||||
handler(NO);
|
||||
}
|
||||
|
||||
NSMutableArray *rules = [[NSMutableArray alloc] initWithCapacity:receivedRules.count];
|
||||
|
||||
NSArray *receivedRules = resp[kRules];
|
||||
for (NSDictionary *rule in receivedRules) {
|
||||
if (![rule isKindOfClass:[NSDictionary class]]) continue;
|
||||
|
||||
SNTRule *newRule = [[SNTRule alloc] init];
|
||||
newRule.SHA1 = rule[@"sha1"];
|
||||
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;
|
||||
}
|
||||
|
||||
[rules addObject:newRule];
|
||||
[progress.downloadedRules addObject:newRule];
|
||||
}
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRules:rules withReply:^{
|
||||
LOGI(@"Downloaded %d rule(s)", rules.count);
|
||||
|
||||
if (resp[@"cursor"]) {
|
||||
[self ruleDownloadWithCursor:resp[@"cursor"]
|
||||
url:url
|
||||
session:session
|
||||
progress:progress
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
} else {
|
||||
if (resp[kCursor]) {
|
||||
[self ruleDownloadWithCursor:resp[kCursor]
|
||||
url:url
|
||||
session:session
|
||||
progress:progress
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
} else {
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRules:progress.downloadedRules withReply:^{
|
||||
if (progress.downloadedRules.count) {
|
||||
LOGI(@"Added %d rule(s)", progress.downloadedRules.count);
|
||||
}
|
||||
handler(YES);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -29,4 +29,7 @@
|
||||
/// Log upload URL sent from server
|
||||
@property NSURL *uploadLogURL;
|
||||
|
||||
/// Rules downloaded from server
|
||||
@property NSMutableArray *downloadedRules;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
|
||||
@@ -1,5 +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.
|
||||
|
||||
///
|
||||
/// This is a simple ASN.1 decoder that utilizes Apple's SecAsn1Decode
|
||||
/// to parse the @c distinguishedNames property of NSURLProtectionSpace.
|
||||
///
|
||||
@interface SNTDERDecoder : NSObject
|
||||
|
||||
@property(readonly) NSString *commonName;
|
||||
@@ -7,9 +23,13 @@
|
||||
@property(readonly) NSString *organizationalUnit;
|
||||
@property(readonly) NSString *countryName;
|
||||
|
||||
/// Designated initializer. Pass in one of the NSData objects in the
|
||||
/// NSURLProtectionSpace.distinguishedNames array
|
||||
/// Returns nil if decoding fails to find any expected objects
|
||||
///
|
||||
/// Designated initializer.
|
||||
///
|
||||
/// @param data one of the objects in the
|
||||
/// NSURLProtectionSpace.distinguishedNames array
|
||||
/// @return nil if decoding fails to find any expected objects
|
||||
///
|
||||
- (instancetype)initWithData:(NSData *)data;
|
||||
|
||||
@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.
|
||||
|
||||
#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
|
||||
@@ -2,17 +2,17 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.santad</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Google, Inc.</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.7</string>
|
||||
<string>TO.BE.FILLED</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>TO.BE.FILLED</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -12,10 +12,14 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
/// The main controller class for santad
|
||||
///
|
||||
/// The main controller class for santad
|
||||
///
|
||||
@interface SNTApplication : NSObject
|
||||
|
||||
/// Begins fielding requests from the driver
|
||||
- (int)run;
|
||||
///
|
||||
/// Begins fielding requests from the driver
|
||||
///
|
||||
- (void)run;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2014 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -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,29 +105,21 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
- (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:^BOOL(santa_message_t message) {
|
||||
[self.driverManager listenWithBlock:^(santa_message_t message) {
|
||||
@autoreleasepool {
|
||||
switch (message.action) {
|
||||
case ACTION_REQUEST_SHUTDOWN: {
|
||||
LOGI(@"Driver requested a shutdown");
|
||||
// Sleep before exiting to give driver chance to ready itself
|
||||
sleep(10);
|
||||
return NO;
|
||||
exit(0);
|
||||
}
|
||||
case ACTION_REQUEST_CHECKBW: {
|
||||
// Validate the binary aynchronously on a concurrent queue so we don't
|
||||
@@ -136,23 +131,21 @@
|
||||
userName = @(user->pw_name);
|
||||
}
|
||||
|
||||
[self.execController validateBinaryWithSHA1:@(message.sha1)
|
||||
path:@(message.path)
|
||||
[self.execController validateBinaryWithPath:@(message.path)
|
||||
userName:userName
|
||||
pid:@(message.pid)
|
||||
ppid:@(message.ppid)
|
||||
vnodeId:message.vnode_id];
|
||||
});
|
||||
return YES;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOGE(@"Received request without an action");
|
||||
return NO;
|
||||
LOGE(@"Received request without a valid action: %d", message.action);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user