mirror of
https://github.com/google/santa.git
synced 2026-01-15 09:17:59 -05:00
Compare commits
314 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08697d9daf | ||
|
|
8959871988 | ||
|
|
bb43a04992 | ||
|
|
5f93dc7991 | ||
|
|
9be8eb223c | ||
|
|
e8b6c47e0f | ||
|
|
697d442afb | ||
|
|
5dbd261b5a | ||
|
|
9bc94ca658 | ||
|
|
4404b5f849 | ||
|
|
6a4b73b8a9 | ||
|
|
b6146224b3 | ||
|
|
e3593c1b0c | ||
|
|
90a2f10da6 | ||
|
|
60bab1c004 | ||
|
|
0898940d0b | ||
|
|
38b65b0ca4 | ||
|
|
d36ce5eefc | ||
|
|
ff99ab9cfe | ||
|
|
64995367c3 | ||
|
|
c67f0ffc11 | ||
|
|
d5403ae112 | ||
|
|
d21d64cbfe | ||
|
|
347ee3c4f5 | ||
|
|
77ed1cca29 | ||
|
|
cfac7dbb37 | ||
|
|
f27d72f3f9 | ||
|
|
3cd93b287e | ||
|
|
5e5605881b | ||
|
|
a9b48610df | ||
|
|
3cca09a48c | ||
|
|
3134448eac | ||
|
|
663bdf945b | ||
|
|
e94d1175e7 | ||
|
|
e20b761965 | ||
|
|
90c64812d0 | ||
|
|
08d368fc49 | ||
|
|
39385f0bff | ||
|
|
8bc3418ce1 | ||
|
|
a145700398 | ||
|
|
409535e617 | ||
|
|
f625016efe | ||
|
|
f4c94ab1d7 | ||
|
|
8234706dd3 | ||
|
|
1a31dc870f | ||
|
|
a1712858c5 | ||
|
|
0059e768b9 | ||
|
|
4fe1550bd2 | ||
|
|
0c182c8a7f | ||
|
|
bcdf746def | ||
|
|
bc13ac3a98 | ||
|
|
a894e018cd | ||
|
|
cbecfd444d | ||
|
|
357e5ef963 | ||
|
|
60594c9f03 | ||
|
|
44b5bae8da | ||
|
|
2e856196c5 | ||
|
|
8672187c02 | ||
|
|
cf251c45b8 | ||
|
|
385c03096d | ||
|
|
f323f5e3de | ||
|
|
9562ee86cd | ||
|
|
adfb4bc861 | ||
|
|
957232ca40 | ||
|
|
44c9d9aead | ||
|
|
f95245cedd | ||
|
|
3c034adf48 | ||
|
|
abd3c5a06d | ||
|
|
ca4951a475 | ||
|
|
e751a3d307 | ||
|
|
2a8bdfd714 | ||
|
|
be9dca3ee2 | ||
|
|
32707fb501 | ||
|
|
d72547e187 | ||
|
|
9150ddffb1 | ||
|
|
d5c1d66c2f | ||
|
|
536b8969ed | ||
|
|
0db3b6d955 | ||
|
|
78bb9a1bd6 | ||
|
|
567e0b6431 | ||
|
|
f2f27c5675 | ||
|
|
5a7ac2287b | ||
|
|
f82da21b75 | ||
|
|
969a5ef94e | ||
|
|
fd7ad07193 | ||
|
|
3f5400b264 | ||
|
|
466b5ed491 | ||
|
|
25f1b71f10 | ||
|
|
d1295f97b9 | ||
|
|
f5eb274aa0 | ||
|
|
58b9dab74f | ||
|
|
9f6b6d10dc | ||
|
|
57f6e516c2 | ||
|
|
8cd9898cf3 | ||
|
|
d53b04213a | ||
|
|
ac99bd1070 | ||
|
|
30df44df96 | ||
|
|
fc55b86f30 | ||
|
|
59ffb67554 | ||
|
|
d46b156b85 | ||
|
|
6492e70599 | ||
|
|
bc5d0f8685 | ||
|
|
838da16da1 | ||
|
|
6e242bf98d | ||
|
|
be1e66c29d | ||
|
|
57866308e3 | ||
|
|
63bc8fca2d | ||
|
|
408712f00f | ||
|
|
8cb6046f94 | ||
|
|
297fb4cb68 | ||
|
|
1501d413f0 | ||
|
|
e747ace0f3 | ||
|
|
6b96f36b2b | ||
|
|
f16fa691b5 | ||
|
|
4fd5e1139f | ||
|
|
0b33079833 | ||
|
|
6069ed5801 | ||
|
|
c2a9061ea2 | ||
|
|
ee963d62a4 | ||
|
|
c12adbc8e6 | ||
|
|
e6b20bcce6 | ||
|
|
10333bba01 | ||
|
|
437764e6fc | ||
|
|
460dd6aa8b | ||
|
|
0a511468e3 | ||
|
|
96517573e7 | ||
|
|
c996921c22 | ||
|
|
8365e00a50 | ||
|
|
a629e6cff1 | ||
|
|
cbb786c6d1 | ||
|
|
49b169ec36 | ||
|
|
41d1d7e3de | ||
|
|
323a38dc21 | ||
|
|
c37f1eb006 | ||
|
|
b7b2b5b630 | ||
|
|
2486cfdcff | ||
|
|
4231781178 | ||
|
|
7ba886ed18 | ||
|
|
8096701fbd | ||
|
|
16531d18c8 | ||
|
|
ef0cc2fffd | ||
|
|
f2dc7fb4b0 | ||
|
|
707e9a11d4 | ||
|
|
aef3d57dcf | ||
|
|
cfb38068f8 | ||
|
|
ca19d9fde7 | ||
|
|
e19aab36bd | ||
|
|
111540f0a8 | ||
|
|
88897477b6 | ||
|
|
a9d6e42d5a | ||
|
|
8b5720b291 | ||
|
|
2d9f392efc | ||
|
|
76844eb77d | ||
|
|
2db996f8e0 | ||
|
|
6c27ac60a1 | ||
|
|
d4c4b26c3b | ||
|
|
50614f589c | ||
|
|
0292d4e956 | ||
|
|
4e1e4cde3b | ||
|
|
c86f0e7c80 | ||
|
|
77b8edda79 | ||
|
|
f3d098c521 | ||
|
|
0afe465ac5 | ||
|
|
472558a03c | ||
|
|
dfef7d8567 | ||
|
|
925903e07d | ||
|
|
a43c0ee295 | ||
|
|
1e82b5abc6 | ||
|
|
7502dbdec6 | ||
|
|
217ad25531 | ||
|
|
7c3b533679 | ||
|
|
2c4ba45988 | ||
|
|
26ee0a68d1 | ||
|
|
27eb2e9cff | ||
|
|
9431d954b5 | ||
|
|
1a2d8b55f8 | ||
|
|
d27a26ca50 | ||
|
|
56d4a6b9fb | ||
|
|
28a94cd56a | ||
|
|
4344fc3d7d | ||
|
|
40431d835e | ||
|
|
942804c478 | ||
|
|
d109aae6ef | ||
|
|
b89040c37a | ||
|
|
63aefb4654 | ||
|
|
1c92e968e3 | ||
|
|
c1b7f9ae63 | ||
|
|
0507bc83d2 | ||
|
|
7028c24425 | ||
|
|
6ede057521 | ||
|
|
6f2ccca60a | ||
|
|
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
|
||||
|
||||
8
.travis.yml
Normal file
8
.travis.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
language: objective-c
|
||||
|
||||
before_install:
|
||||
- gem install cocoapods xcpretty
|
||||
|
||||
script:
|
||||
- xcodebuild -workspace Santa.xcworkspace -scheme All build test CODE_SIGN_IDENTITY='' | xcpretty -sc && exit ${PIPESTATUS[0]}
|
||||
@@ -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
|
||||
|
||||
84
Conf/Package/Makefile
Normal file
84
Conf/Package/Makefile
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# Package Makefile for Santa
|
||||
# Requires TheLuggage (github.com/unixorn/luggage) to be installed
|
||||
#
|
||||
# Will generate a package based on the latest release. You can replace
|
||||
# the PACKAGE_VERSION variable with a specific variable instead if you wish.
|
||||
#
|
||||
|
||||
LUGGAGE:=/usr/local/share/luggage/luggage.make
|
||||
include ${LUGGAGE}
|
||||
|
||||
TITLE:=santa
|
||||
REVERSE_DOMAIN:=com.google
|
||||
|
||||
# Get latest Release version using the GitHub API. Each release is bound to a
|
||||
# git tag, which should always be a semantic version number. The most recent
|
||||
# release is always first in the API result.
|
||||
PACKAGE_VERSION:=$(shell curl -fs https://api.github.com/repos/google/santa/releases |\
|
||||
python -c 'import json, sys; print json.load(sys.stdin)[0]["tag_name"]' 2>/dev/null)
|
||||
|
||||
# Get the download URL for the latest Release. Each release should have a
|
||||
# tarball named santa-$version.tar.bz2 containing all of the files associated
|
||||
# with that release. The tarball layout is:
|
||||
#
|
||||
# santa-$version.tar.bz2
|
||||
# +--santa-$version
|
||||
# |-- binaries
|
||||
# | |-- santa-driver.kext
|
||||
# | |-- Santa.app
|
||||
# |-- conf
|
||||
# | |-- install.sh
|
||||
# | |-- com.google.santad.plist
|
||||
# | |-- com.google.santagui.plist
|
||||
# | +-- com.google.santa.asl.conf
|
||||
# +--dsym
|
||||
# |-- santa-driver.kext.dSYM
|
||||
# |-- Santa.app.dSYM
|
||||
# |-- santad.dSYM
|
||||
# +-- santactl.dSYM
|
||||
PACKAGE_DOWNLOAD_URL:="https://github.com/google/santa/releases/download/${PACKAGE_VERSION}/santa-${PACKAGE_VERSION}.tar.bz2"
|
||||
|
||||
PAYLOAD:=pack-Library-Extensions-santa-driver.kext \
|
||||
pack-applications-Santa.app \
|
||||
pack-Library-LaunchDaemons-com.google.santad.plist \
|
||||
pack-Library-LaunchAgents-com.google.santagui.plist \
|
||||
pack-etc-asl-com.google.santa.asl.conf \
|
||||
pack-script-preinstall \
|
||||
pack-script-postinstall
|
||||
|
||||
santa-driver.kext: download
|
||||
Santa.app: download
|
||||
com.google.santad.plist: download
|
||||
com.google.santagui.plist: download
|
||||
com.google.santa.asl.conf: download
|
||||
|
||||
download:
|
||||
$(if $(PACKAGE_VERSION),, $(error GitHub API returned unexpected result. Wait a while and try again))
|
||||
|
||||
@curl -fL ${PACKAGE_DOWNLOAD_URL} | tar xvj --strip=2
|
||||
@rm -rf *.dSYM
|
||||
|
||||
pack-etc-asl-com.google.santa.asl.conf: com.google.santa.asl.conf l_private_etc
|
||||
@sudo mkdir -p ${WORK_D}/private/etc/asl
|
||||
@sudo chown root:wheel ${WORK_D}/private/etc/asl
|
||||
@sudo chmod 755 ${WORK_D}/private/etc/asl
|
||||
@sudo install -m 644 -o root -g wheel com.google.santa.asl.conf ${WORK_D}/private/etc/asl
|
||||
|
||||
pack-Library-Extensions-santa-driver.kext: santa-driver.kext l_Library
|
||||
@sudo mkdir -p ${WORK_D}/Library/Extensions
|
||||
@sudo ${DITTO} --noqtn santa-driver.kext ${WORK_D}/Library/Extensions/santa-driver.kext
|
||||
@sudo chown -R root:wheel ${WORK_D}/Library/Extensions/santa-driver.kext
|
||||
@sudo chmod -R 755 ${WORK_D}/Library/Extensions/santa-driver.kext
|
||||
|
||||
clean: myclean
|
||||
|
||||
myclean:
|
||||
@rm -rf *.dSYM
|
||||
@rm -rf Santa.app
|
||||
@rm -rf santa-driver.kext
|
||||
@rm -f config.plist
|
||||
@rm -f com.google.santa.asl.conf
|
||||
@rm -f com.google.santad.plist
|
||||
@rm -f com.google.santagui.plist
|
||||
@rm -f install.sh
|
||||
27
Conf/Package/postinstall
Normal file
27
Conf/Package/postinstall
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Load the kernel extension, santad, sync client
|
||||
# If a user is logged in, also load the GUI agent.
|
||||
# If the target volume is not /, do nothing
|
||||
|
||||
[[ $3 != "/" ]] && exit 0
|
||||
|
||||
# Restart syslogd to pick up ASL configuration change
|
||||
/usr/bin/killall -HUP syslogd
|
||||
|
||||
/sbin/kextload /Library/Extensions/santa-driver.kext
|
||||
|
||||
sleep 1
|
||||
|
||||
/bin/launchctl load -w /Library/LaunchDaemons/com.google.santad.plist
|
||||
|
||||
sleep 1
|
||||
|
||||
# Create hopefully useful symlink for santactl
|
||||
/bin/ln -s /Library/Extensions/santa-driver.kext/Contents/MacOS/santactl /usr/local/bin
|
||||
|
||||
user=$(/usr/bin/stat -f '%u' /dev/console)
|
||||
[[ -z "$user" ]] && exit 0
|
||||
/bin/launchctl asuser ${user} /bin/launchctl load /Library/LaunchAgents/com.google.santagui.plist
|
||||
|
||||
exit 0
|
||||
26
Conf/Package/preinstall
Normal file
26
Conf/Package/preinstall
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Unload the kernel extension, santad, sync client
|
||||
# If a user is logged in, also unload the GUI agent.
|
||||
# If the target volume is not /, do nothing
|
||||
|
||||
[[ $3 != "/" ]] && exit 0
|
||||
|
||||
/bin/launchctl remove com.google.santad
|
||||
|
||||
sleep 1
|
||||
|
||||
/sbin/kextunload -b com.google.santa-driver >/dev/null 2>&1
|
||||
|
||||
# Remove cruft from old Santa versions
|
||||
/bin/rm /usr/libexec/santad
|
||||
/bin/rm /usr/sbin/santactl
|
||||
/bin/launchctl remove com.google.santasync
|
||||
/bin/rm /Library/LaunchDaemons/com.google.santasync.plist
|
||||
|
||||
sleep 1
|
||||
|
||||
user=$(/usr/bin/stat -f '%u' /dev/console)
|
||||
[[ -n "$user" ]] && /bin/launchctl asuser ${user} /bin/launchctl remove com.google.santagui
|
||||
|
||||
exit 0
|
||||
@@ -1,2 +1,8 @@
|
||||
# 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"
|
||||
> /var/log/santa.log format="[$((Time)(utc.3))] $Message" mode=0644 rotate=seq compress file_max=10M all_max=100M uid=0 gid=0
|
||||
? [S= Message santa-driver:] claim
|
||||
? [S= Message santa-driver:] file /var/log/santa.log
|
||||
? [= Sender santad] claim
|
||||
? [= Sender santad] file /var/log/santa.log
|
||||
? [= Sender santactl] claim
|
||||
? [= Sender santactl] file /var/log/santa.log
|
||||
|
||||
@@ -6,19 +6,15 @@
|
||||
<string>com.google.santad</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/libexec/santad</string>
|
||||
<string>/Library/Extensions/santa-driver.kext/Contents/MacOS/santad</string>
|
||||
</array>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>SantaXPCNotifications</key>
|
||||
<true/>
|
||||
<key>SantaXPCControl</key>
|
||||
<true/>
|
||||
<key>SantaXPCNotifications</key>
|
||||
<true/>
|
||||
<key>SantaXPCControl</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/santa.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/santa.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
|
||||
@@ -8,11 +8,9 @@
|
||||
<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/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.google.santasync</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/sbin/santactl</string>
|
||||
<string>sync</string>
|
||||
</array>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/santa.log</string>
|
||||
<key>ProcessType</key>
|
||||
<string>Background</string>
|
||||
<key>StartInterval</key>
|
||||
<integer>600</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
58
Conf/install.sh
Executable file
58
Conf/install.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "binaries" ]]; then
|
||||
SOURCE="."
|
||||
elif [[ -d "../binaries" ]]; then
|
||||
SOURCE=".."
|
||||
else
|
||||
echo "Can't find binaries, run install.sh from inside the conf directory" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine if anyone is logged into the GUI
|
||||
GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
|
||||
|
||||
# Unload santad and scheduled sync job.
|
||||
/bin/launchctl remove com.google.santad >/dev/null 2>&1
|
||||
|
||||
# Unload kext.
|
||||
/sbin/kextunload -b com.google.santa-driver >/dev/null 2>&1
|
||||
|
||||
# Unload GUI agent if someone is logged in.
|
||||
[[ -n "$GUI_USER" ]] && \
|
||||
/bin/launchctl asuser ${GUI_USER} /bin/launchctl remove /Library/LaunchAgents/com.google.santagui.plist
|
||||
|
||||
# Cleanup cruft from old versions
|
||||
/bin/launchctl remove com.google.santasync >/dev/null 2>&1
|
||||
/bin/rm /Library/LaunchDaemons/com.google.santasync.plist >/dev/null 2>&1
|
||||
/bin/rm /usr/libexec/santad >/dev/null 2>&1
|
||||
/bin/rm /usr/sbin/santactl >/dev/null 2>&1
|
||||
|
||||
# Copy new files.
|
||||
/bin/cp -r ${SOURCE}/binaries/santa-driver.kext /Library/Extensions
|
||||
/bin/cp -r ${SOURCE}/binaries/Santa.app /Applications
|
||||
/bin/ln -s /Library/Extensions/santa-driver.kext/Contents/MacOS/santactl /usr/local/bin
|
||||
|
||||
/bin/cp ${SOURCE}/conf/com.google.santad.plist /Library/LaunchDaemons
|
||||
/bin/cp ${SOURCE}/conf/com.google.santagui.plist /Library/LaunchAgents
|
||||
/bin/cp ${SOURCE}/conf/com.google.santa.asl.conf /etc/asl/
|
||||
|
||||
# Reload syslogd to pick up ASL configuration change.
|
||||
/usr/bin/killall -HUP syslogd
|
||||
|
||||
# Load kext.
|
||||
/sbin/kextload /Library/Extensions/santa-driver.kext
|
||||
|
||||
# Load santad and scheduled sync jobs.
|
||||
/bin/launchctl load /Library/LaunchDaemons/com.google.santad.plist
|
||||
|
||||
# Load GUI agent if someone is logged in.
|
||||
[[ -n "$GUI_USER" ]] && \
|
||||
/bin/launchctl asuser ${GUI_USER} /bin/launchctl load /Library/LaunchAgents/com.google.santagui.plist
|
||||
|
||||
exit 0
|
||||
15
Podfile
15
Podfile
@@ -1,9 +1,22 @@
|
||||
platform :osx, "10.8"
|
||||
platform :osx, "10.9"
|
||||
|
||||
inhibit_all_warnings!
|
||||
|
||||
target :santad do
|
||||
pod 'FMDB'
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_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.38.0
|
||||
|
||||
47
README.md
47
README.md
@@ -1,7 +1,7 @@
|
||||
Santa
|
||||
Santa [](https://travis-ci.org/google/santa)
|
||||
=====
|
||||
|
||||
Santa is a binary whitelisting/blacklisting system for Mac OS X. It consists of
|
||||
Santa is a binary whitelisting/blacklisting system for OS X. It consists of
|
||||
a kernel extension that monitors for executions, a userland daemon that makes
|
||||
execution decisions based on the contents of a SQLite database, a GUI agent that
|
||||
notifies the user in case of a block decision and a command-line utility for
|
||||
@@ -46,21 +46,24 @@ server.
|
||||
programming interfaces to do its job. This means that the kext code should
|
||||
continue to work across OS versions.
|
||||
|
||||
Intentions and Expectations
|
||||
===========================
|
||||
No single system or process will stop *all* attacks, or provide 100% security. Santa is written with the intention of helping protect users from themselves. People often download malware and trust it, giving the malware credentials, or allowing unknown software to exfiltrate more data about your system. As a centrally managed component, Santa can help stop the spread of malware among a larger fleet of machines. Additionally, Santa can aid in analyzing what is running in your fleet.
|
||||
|
||||
Santa is part of a defense-in-depth strategy, and you should continue to protect hosts in whatever other ways you see fit.
|
||||
|
||||
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.
|
||||
* Santa only blocks execution (execve and variants), it doesn't protect against
|
||||
dynamic libraries loaded with dlopen, libraries on disk that have been replaced or
|
||||
libraries loaded using DYLD_INSERT_LIBRARIES. We are working on also protecting
|
||||
against these avenues of attack.
|
||||
|
||||
* 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
|
||||
@@ -87,7 +90,6 @@ option) if it would be useful to others.
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
```sh
|
||||
git clone https://github.com/google/santa
|
||||
cd santa
|
||||
@@ -105,31 +107,34 @@ and for security-reasons parts of Santa will not operate properly if not signed.
|
||||
|
||||
Kext Signing
|
||||
============
|
||||
|
||||
10.9 requires a special Developer ID certificate to sign kernel extensions and
|
||||
if the kext is not signed with one of these special certificates a warning will
|
||||
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
|
||||
============
|
||||
|
||||
Patches to this project are very much welcome. Please see the [CONTRIBUTING](https://github.com/google/santa/blob/master/CONTRIBUTING.md)
|
||||
file.
|
||||
|
||||
Disclaimer
|
||||
==========
|
||||
|
||||
This is **not** an official Google product.
|
||||
|
||||
142
Rakefile
142
Rakefile
@@ -1,65 +1,47 @@
|
||||
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"
|
||||
WORKSPACE = 'Santa.xcworkspace'
|
||||
DEFAULT_SCHEME = 'All'
|
||||
OUTPUT_PATH = 'Build'
|
||||
DIST_PATH = 'Dist'
|
||||
BINARIES = ['Santa.app', 'santa-driver.kext']
|
||||
DSYMS = ['Santa.app.dSYM', 'santa-driver.kext.dSYM', 'santad.dSYM', 'santactl.dSYM']
|
||||
XCPRETTY_DEFAULTS = '-sc'
|
||||
XCODEBUILD_DEFAULTS = "-workspace #{WORKSPACE} -derivedDataPath #{OUTPUT_PATH} -parallelizeTargets"
|
||||
|
||||
task :default do
|
||||
system("rake -sT")
|
||||
end
|
||||
|
||||
def run_and_output_on_fail(cmd)
|
||||
output=`#{cmd} 2>&1`
|
||||
if not $?.success?
|
||||
raise output
|
||||
end
|
||||
end
|
||||
|
||||
def run_and_output_with_color(cmd)
|
||||
output=`#{cmd} 2>&1`
|
||||
|
||||
has_output = false
|
||||
output.scan(/((Test Suite|Test Case|Executed).*)$/) do |match|
|
||||
has_output = true
|
||||
out = match[0]
|
||||
if out.include?("passed")
|
||||
puts "\e[32m#{out}\e[0m"
|
||||
elsif out.include?("failed")
|
||||
puts "\e[31m#{out}\e[0m"
|
||||
else
|
||||
puts out
|
||||
end
|
||||
end
|
||||
|
||||
if not has_output
|
||||
raise output
|
||||
def xcodebuild(opts)
|
||||
if system "xcodebuild #{XCODEBUILD_DEFAULTS} #{opts} | " \
|
||||
"xcpretty #{XCPRETTY_DEFAULTS} && " \
|
||||
"exit ${PIPESTATUS[0]}"
|
||||
puts "\e[32mPass\e[0m"
|
||||
else
|
||||
raise "\e[31mFail\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
unless system 'xcpretty -v >/dev/null 2>&1'
|
||||
puts "xcpretty is not installed. Install with 'sudo gem install xcpretty'"
|
||||
end
|
||||
end
|
||||
|
||||
task :remove_existing do
|
||||
system 'sudo rm -rf /santa-driver.kext'
|
||||
system 'sudo rm -rf /Library/Extensions/santa-driver.kext'
|
||||
system 'sudo rm -rf /Applications/Santa.app'
|
||||
system 'sudo rm /usr/libexec/santad'
|
||||
system 'sudo rm /usr/sbin/santactl'
|
||||
end
|
||||
|
||||
desc "Clean"
|
||||
task :clean => :init do
|
||||
puts "Cleaning"
|
||||
run_and_output_on_fail("xcodebuild #{XCODE_DEFAULTS} clean")
|
||||
xcodebuild("-scheme All clean")
|
||||
FileUtils.rm_rf(OUTPUT_PATH)
|
||||
FileUtils.rm_rf(DIST_PATH)
|
||||
end
|
||||
|
||||
# Build
|
||||
@@ -77,7 +59,7 @@ 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")
|
||||
xcodebuild("-scheme All -configuration #{config} build")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,25 +79,49 @@ namespace :install do
|
||||
task :install, [:configuration] do |t, args|
|
||||
config = args[:configuration]
|
||||
system 'sudo cp conf/com.google.santad.plist /Library/LaunchDaemons'
|
||||
system 'sudo cp conf/com.google.santasync.plist /Library/LaunchDaemons'
|
||||
system 'sudo cp conf/com.google.santagui.plist /Library/LaunchAgents'
|
||||
system 'sudo cp conf/com.google.santa.asl.conf /etc/asl'
|
||||
Rake::Task['build:build'].invoke(config)
|
||||
puts "Installing with configuration: #{config}"
|
||||
Rake::Task['remove_existing'].invoke()
|
||||
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/santa-driver.kext /"
|
||||
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/santa-driver.kext /Library/Extensions"
|
||||
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/Santa.app /Applications"
|
||||
system "sudo cp #{OUTPUT_PATH}/Products/#{config}/santad /usr/libexec"
|
||||
system "sudo cp #{OUTPUT_PATH}/Products/#{config}/santactl /usr/sbin"
|
||||
end
|
||||
end
|
||||
|
||||
# Dist
|
||||
task :dist do
|
||||
desc "Create distribution folder"
|
||||
|
||||
Rake::Task['clean'].invoke()
|
||||
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")
|
||||
end
|
||||
|
||||
DSYMS.each do |x|
|
||||
FileUtils.cp_r("#{OUTPUT_PATH}/Products/Release/#{x}", "#{DIST_PATH}/dsym")
|
||||
end
|
||||
|
||||
|
||||
Dir.glob("Conf/*") {|x| File.directory?(x) or 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")
|
||||
xcodebuild("-scheme LogicTests test")
|
||||
end
|
||||
|
||||
desc "Tests: Kernel"
|
||||
@@ -123,16 +129,16 @@ namespace :tests do
|
||||
Rake::Task['unload'].invoke()
|
||||
Rake::Task['install:debug'].invoke()
|
||||
Rake::Task['load_kext'].invoke
|
||||
timeout = 30
|
||||
puts "Running kernel tests with a #{timeout} second timeout"
|
||||
FileUtils.mkdir_p("/tmp/santa_kerneltests_tmp")
|
||||
begin
|
||||
Timeout::timeout(timeout) {
|
||||
system "sudo #{OUTPUT_PATH}/Products/Debug/KernelTests"
|
||||
}
|
||||
rescue Timeout::Error
|
||||
puts "ERROR: tests ran for longer than #{timeout} seconds and were killed."
|
||||
puts "\033[?25l\033[12h" # hide cursor
|
||||
puts "Running kernel tests"
|
||||
system "cd /tmp/santa_kerneltests_tmp && sudo #{Dir.pwd}/#{OUTPUT_PATH}/Products/Debug/KernelTests"
|
||||
rescue Exception
|
||||
puts "\033[?25h\033[12l\n\n" # unhide cursor
|
||||
FileUtils.rm_rf("/tmp/santa_kerneltests_tmp")
|
||||
Rake::Task['unload_kext'].execute
|
||||
end
|
||||
Rake::Task['unload_kext'].execute
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,12 +150,12 @@ 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
|
||||
puts "Unloading GUI agent"
|
||||
system "sudo killall Santa 2>/dev/null"
|
||||
system "launchctl unload /Library/LaunchAgents/com.google.santagui.plist 2>/dev/null"
|
||||
end
|
||||
|
||||
desc "Unload"
|
||||
@@ -162,12 +168,12 @@ end
|
||||
|
||||
task :load_kext do
|
||||
puts "Loading kernel extension"
|
||||
system "sudo kextload /santa-driver.kext"
|
||||
system "sudo kextload /Library/Extensions/santa-driver.kext"
|
||||
end
|
||||
|
||||
task :load_gui do
|
||||
puts "Loading GUI agent"
|
||||
system "open /Applications/Santa.app"
|
||||
system "launchctl load /Library/LaunchAgents/com.google.santagui.plist 2>/dev/null"
|
||||
end
|
||||
|
||||
desc "Load"
|
||||
@@ -188,23 +194,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 */; };
|
||||
@@ -69,15 +69,16 @@
|
||||
0D3AFBF018FB4C6C0087BCEE /* SNTDriverManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */; };
|
||||
0D3AFBF618FB4C7E0087BCEE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D385DB7180DE4A900418BC6 /* Cocoa.framework */; };
|
||||
0D3AFBF818FB4C870087BCEE /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0D416401191974F1006A356A /* SNTCommandSyncStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncStatus.m */; };
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncState.m */; };
|
||||
0D41640519197AD7006A356A /* SNTCommandSyncEventUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D41640419197AD7006A356A /* SNTCommandSyncEventUpload.m */; };
|
||||
0D41DAD41A7C28C800A890FE /* SNTEventTableTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */; };
|
||||
0D42D2B519D1D98A00955F08 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */; };
|
||||
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,19 @@
|
||||
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 */; };
|
||||
0DB537871AFD36EB00487F92 /* SNTRuleTableTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB537861AFD36EB00487F92 /* SNTRuleTableTest.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 */; };
|
||||
0DC765EA1B28D9EA00BAE651 /* santad in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0D9A7F3D1759330500035EB5 /* santad */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
0DC765EB1B28D9EA00BAE651 /* santactl in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0D35BD9E18FD71CE00921A21 /* santactl */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
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 +139,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 +148,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 */
|
||||
@@ -191,17 +205,33 @@
|
||||
remoteGlobalIDString = 0D9A7F3C1759330400035EB5;
|
||||
remoteInfo = santad;
|
||||
};
|
||||
0DC765E51B28D9C600BAE651 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0D91BCA8174E8A6500131A7D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 0D9A7F3C1759330400035EB5;
|
||||
remoteInfo = santad;
|
||||
};
|
||||
0DC765E71B28D9C600BAE651 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0D91BCA8174E8A6500131A7D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 0D35BD9D18FD71CE00921A21;
|
||||
remoteInfo = santactl;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
0D9A7F3B1759330400035EB5 /* CopyFiles */ = {
|
||||
0DC765E91B28D9CB00BAE651 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 6;
|
||||
files = (
|
||||
0DC765EA1B28D9EA00BAE651 /* santad in CopyFiles */,
|
||||
0DC765EB1B28D9EA00BAE651 /* santactl in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
@@ -222,13 +252,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 +271,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>"; };
|
||||
@@ -255,10 +284,11 @@
|
||||
0D385DEF180DE51600418BC6 /* SNTNotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTNotificationManager.m; sourceTree = "<group>"; };
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCConnectionTest.m; sourceTree = "<group>"; };
|
||||
0D3AFBF718FB4C870087BCEE /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncStatus.h; sourceTree = "<group>"; };
|
||||
0D416400191974F1006A356A /* SNTCommandSyncStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncStatus.m; sourceTree = "<group>"; };
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncState.h; sourceTree = "<group>"; };
|
||||
0D416400191974F1006A356A /* SNTCommandSyncState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncState.m; sourceTree = "<group>"; };
|
||||
0D41640319197AD7006A356A /* SNTCommandSyncEventUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncEventUpload.h; sourceTree = "<group>"; };
|
||||
0D41640419197AD7006A356A /* SNTCommandSyncEventUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncEventUpload.m; sourceTree = "<group>"; };
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventTableTest.m; sourceTree = "<group>"; };
|
||||
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 +331,19 @@
|
||||
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>"; };
|
||||
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTRuleTableTest.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 +355,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 +394,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 +402,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 +413,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 +446,14 @@
|
||||
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 */,
|
||||
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */,
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
|
||||
);
|
||||
path = LogicTests;
|
||||
@@ -420,12 +462,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 +481,10 @@
|
||||
0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */,
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */,
|
||||
0DE4C8A318FF3AFA00466D04 /* flushcache */,
|
||||
409232751A51914400A04527 /* rule */,
|
||||
0D827E6819DF4F3F006EC811 /* status */,
|
||||
0D35BDB618FD84FC00921A21 /* sync */,
|
||||
0DB390971AB1E0F200614002 /* version */,
|
||||
0D35BDA318FD71CE00921A21 /* Resources */,
|
||||
);
|
||||
name = santactl;
|
||||
@@ -449,8 +494,8 @@
|
||||
0D35BDA318FD71CE00921A21 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */,
|
||||
0D28E5E41926B55600280F87 /* santactl-Info.plist */,
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -458,9 +503,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 */,
|
||||
@@ -471,8 +520,8 @@
|
||||
0DCD605B19117A90006B445C /* SNTCommandSyncPreflight.m */,
|
||||
0D0A1EC1191998C900B8450F /* SNTCommandSyncRuleDownload.h */,
|
||||
0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */,
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncStatus.h */,
|
||||
0D416400191974F1006A356A /* SNTCommandSyncStatus.m */,
|
||||
0D4163FF191974F1006A356A /* SNTCommandSyncState.h */,
|
||||
0D416400191974F1006A356A /* SNTCommandSyncState.m */,
|
||||
0D7FFD491A017D4B00F34435 /* SNTDERDecoder.h */,
|
||||
0D7FFD4A1A017D4B00F34435 /* SNTDERDecoder.m */,
|
||||
);
|
||||
@@ -503,7 +552,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 +617,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 +634,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 +651,6 @@
|
||||
0D91BCD5174E8AAB00131A7D /* common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DCD6040190ACCB8006B445C /* SNTBinaryInfo.h */,
|
||||
0DCD6041190ACCB8006B445C /* SNTBinaryInfo.m */,
|
||||
0D1AF475187C7A2C00D3298D /* SNTCertificate.h */,
|
||||
0D1AF476187C7A2C00D3298D /* SNTCertificate.m */,
|
||||
0D59C0E217710E6000748EBF /* SNTCodesignChecker.h */,
|
||||
@@ -614,11 +660,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 +726,14 @@
|
||||
name = DataLayer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DB390971AB1E0F200614002 /* version */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DB390981AB1E11400614002 /* SNTCommandVersion.m */,
|
||||
);
|
||||
name = version;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0DCD5FBC1909D4FD006B445C /* binaryinfo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -705,6 +761,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 +826,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D35BDA918FD71CE00921A21 /* Build configuration list for PBXNativeTarget "santactl" */;
|
||||
buildPhases = (
|
||||
0DD98E671A5DD02000A754C6 /* Update Version Info */,
|
||||
0D35BD9A18FD71CE00921A21 /* Sources */,
|
||||
0D35BD9B18FD71CE00921A21 /* Frameworks */,
|
||||
);
|
||||
@@ -778,6 +843,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D385DE3180DE4A900418BC6 /* Build configuration list for PBXNativeTarget "Santa" */;
|
||||
buildPhases = (
|
||||
0DD98E681A5DD03E00A754C6 /* Update Version Info */,
|
||||
0D385DB2180DE4A900418BC6 /* Sources */,
|
||||
0D385DB3180DE4A900418BC6 /* Frameworks */,
|
||||
0D385DB4180DE4A900418BC6 /* Resources */,
|
||||
@@ -795,12 +861,17 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D91BCC3174E8A7E00131A7D /* Build configuration list for PBXNativeTarget "santa-driver" */;
|
||||
buildPhases = (
|
||||
0D45F4271A5DCB7A00BF4375 /* Update Version Info */,
|
||||
0DD98E691A5DD5C900A754C6 /* Update Module Version */,
|
||||
0D91BCAE174E8A7E00131A7D /* Sources */,
|
||||
0D91BCB0174E8A7E00131A7D /* Headers */,
|
||||
0DC765E91B28D9CB00BAE651 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
0DC765E61B28D9C600BAE651 /* PBXTargetDependency */,
|
||||
0DC765E81B28D9C600BAE651 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "santa-driver";
|
||||
productName = "santa-driver";
|
||||
@@ -812,9 +883,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 +905,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 +942,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 +960,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 +991,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,25 +1128,29 @@
|
||||
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 */,
|
||||
0D3AFBEF18FB4C6C0087BCEE /* SNTExecutionController.m in Sources */,
|
||||
0D3AFBEC18FB48E70087BCEE /* SNTEventTable.m in Sources */,
|
||||
0DB537871AFD36EB00487F92 /* SNTRuleTableTest.m in Sources */,
|
||||
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 +1170,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 +1178,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 */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncStatus.m in Sources */,
|
||||
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.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 +1202,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 +1216,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 +1236,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 +1245,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 +1254,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 */,
|
||||
@@ -1149,6 +1294,16 @@
|
||||
target = 0D9A7F3C1759330400035EB5 /* santad */;
|
||||
targetProxy = 0D9A7F591759393600035EB5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
0DC765E61B28D9C600BAE651 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 0D9A7F3C1759330400035EB5 /* santad */;
|
||||
targetProxy = 0DC765E51B28D9C600BAE651 /* PBXContainerItemProxy */;
|
||||
};
|
||||
0DC765E81B28D9C600BAE651 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 0D35BD9D18FD71CE00921A21 /* santactl */;
|
||||
targetProxy = 0DC765E71B28D9C600BAE651 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -1181,8 +1336,10 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INSTALL_PATH = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1209,8 +1366,10 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INSTALL_PATH = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1219,7 +1378,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;
|
||||
@@ -1260,6 +1418,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = "Tests/LogicTests/Resources/Tests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WARNING_CFLAGS = "";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1269,7 +1428,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;
|
||||
@@ -1304,6 +1462,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = "Tests/LogicTests/Resources/Tests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WARNING_CFLAGS = "";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Release;
|
||||
@@ -1314,6 +1473,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 +1500,8 @@
|
||||
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";
|
||||
INSTALL_PATH = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
@@ -1352,6 +1513,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 +1534,8 @@
|
||||
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";
|
||||
INSTALL_PATH = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
@@ -1385,6 +1548,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 +1575,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 +1589,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 +1610,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,11 +1624,16 @@
|
||||
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;
|
||||
SDKROOT = macosx;
|
||||
WARNING_CFLAGS = (
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wno-unused-parameter",
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1475,10 +1645,15 @@
|
||||
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;
|
||||
WARNING_CFLAGS = (
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wno-unused-parameter",
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1487,13 +1662,14 @@
|
||||
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;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@@ -1505,14 +1681,17 @@
|
||||
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";
|
||||
WARNING_CFLAGS = "-Wno-deprecated-register";
|
||||
WARNING_CFLAGS = (
|
||||
"-Wno-deprecated-register",
|
||||
"$(inherit)",
|
||||
);
|
||||
WRAPPER_EXTENSION = kext;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1522,13 +1701,14 @@
|
||||
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;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||
@@ -1537,13 +1717,16 @@
|
||||
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";
|
||||
WARNING_CFLAGS = (
|
||||
"-Wno-deprecated-register",
|
||||
"$(inherit)",
|
||||
);
|
||||
WRAPPER_EXTENSION = kext;
|
||||
};
|
||||
name = Release;
|
||||
@@ -1568,6 +1751,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,8 +1773,8 @@
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santad/Resources/santad-Info.plist";
|
||||
INSTALL_PATH = /usr/sbin;
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@@ -1602,6 +1786,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,8 +1801,8 @@
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Source/santad/Resources/santad-Info.plist";
|
||||
INSTALL_PATH = /usr/sbin;
|
||||
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
|
||||
INSTALL_PATH = "";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -49,6 +49,15 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D91BCDC174E8AE600131A7D"
|
||||
BuildableName = "All"
|
||||
BlueprintName = "All"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0600"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -48,7 +48,8 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D0016A1192BCD3C005E7FCD"
|
||||
@@ -66,7 +67,8 @@
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D0016A1192BCD3C005E7FCD"
|
||||
|
||||
96
Santa.xcodeproj/xcshareddata/xcschemes/LogicTests.xcscheme
Normal file
96
Santa.xcodeproj/xcshareddata/xcschemes/LogicTests.xcscheme
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D260DAB18B68E12002A0B55"
|
||||
BuildableName = "LogicTests.xctest"
|
||||
BlueprintName = "LogicTests"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -48,7 +48,8 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D385DB5180DE4A900418BC6"
|
||||
@@ -66,7 +67,8 @@
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D385DB5180DE4A900418BC6"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -39,6 +39,15 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D91BCB3174E8A7E00131A7D"
|
||||
BuildableName = "santa-driver.kext"
|
||||
BlueprintName = "santa-driver"
|
||||
ReferencedContainer = "container:Santa.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -48,7 +48,8 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D35BD9D18FD71CE00921A21"
|
||||
@@ -66,7 +67,8 @@
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D35BD9D18FD71CE00921A21"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -42,13 +42,15 @@
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
debugAsWhichUser = "root"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D9A7F3C1759330400035EB5"
|
||||
@@ -66,7 +68,8 @@
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0D9A7F3C1759330400035EB5"
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
<?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="14E46" 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>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Santa" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES"/>
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="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,32 +37,51 @@
|
||||
<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 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"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="orderOut:" target="-1" id="6oW-zI-zn5"/>
|
||||
</connections>
|
||||
</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="14E46" 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="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
|
||||
<rect key="contentRect" x="167" y="107" width="497" height="356"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1600"/>
|
||||
<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="497" height="356"/>
|
||||
<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="207" y="286" 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,46 +30,23 @@
|
||||
</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="22" y="239" width="454" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="500" id="q9O-xW-hnS"/>
|
||||
<constraint firstAttribute="width" constant="450" 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">
|
||||
<textFieldCell key="cell" selectable="YES" 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"/>
|
||||
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<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="165" y="192" width="294" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="346" id="BYY-2q-Lmb"/>
|
||||
<constraint firstAttribute="width" constant="290" 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,124 @@
|
||||
<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="165" y="142" width="294" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="290" id="4hh-R2-86s"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="charWrapping" selectable="YES" sendsActionOnEndEditing="YES" title="Part of 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.shortenedHash" id="xgu-71-9ZT"/>
|
||||
</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="165" y="167" width="294" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="290" 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="8" 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="eQb-0a-76J">
|
||||
<rect key="frame" x="8" y="117" width="120" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Parent" id="gze-4A-1w5">
|
||||
<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="lvJ-Rk-UT5">
|
||||
<rect key="frame" x="8" y="167" 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="8" y="192" 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="8" y="142" width="120" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Identifier" 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="165" y="92" width="294" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="290" id="on6-pj-m2k"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" 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="IcM-Lt-xTT">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">Unknown</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<box horizontalHuggingPriority="750" title="Line" boxType="custom" borderType="line" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="4Li-ul-zIi">
|
||||
<rect key="frame" x="146" y="92" width="1" height="117"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="1" id="0o1-Jh-epf"/>
|
||||
</constraints>
|
||||
<color key="borderColor" white="0.0" alpha="0.17999999999999999" 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="40" y="168" width="15" height="15"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="15" id="QTm-Iv-m5p"/>
|
||||
<constraint firstAttribute="height" constant="15" 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 +179,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="256" 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 +196,99 @@ 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="132" 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"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="openEventDetails:" target="-2" id="VhL-ql-rCV"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="f1p-GL-O3o">
|
||||
<rect key="frame" x="165" y="117" width="294" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="290" id="h3Y-mO-38F"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" title="Parent Name" id="ieo-WK-aDD">
|
||||
<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.binaryCert" id="eFt-oy-SXL">
|
||||
<binding destination="-2" name="displayPatternValue1" keyPath="self.event.parentName" id="Lce-TO-q9V">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">Not code-signed</string>
|
||||
<string key="NSDisplayPattern">%{value1}@ (%{value2}@)</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="-2" name="displayPatternValue2" keyPath="self.event.ppid" previousBinding="Lce-TO-q9V" id="ofI-kH-F2d">
|
||||
<dictionary key="options">
|
||||
<string key="NSDisplayPattern">%{value1}@ (%{value2}@)</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
</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="f1p-GL-O3o" firstAttribute="centerY" secondItem="eQb-0a-76J" secondAttribute="centerY" id="2Aq-1E-Ybz"/>
|
||||
<constraint firstItem="BbV-3h-mmL" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" priority="500" constant="193" id="2uo-Cm-Tfp"/>
|
||||
<constraint firstItem="h6f-PY-cc0" firstAttribute="top" secondItem="f1p-GL-O3o" secondAttribute="bottom" constant="8" id="496-VQ-Fx5"/>
|
||||
<constraint firstItem="eQb-0a-76J" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="trailing" constant="-116" id="6Q5-Oo-1cI"/>
|
||||
<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="f1p-GL-O3o" firstAttribute="top" secondItem="PXc-xv-A28" secondAttribute="bottom" constant="8" id="E6D-7P-17g"/>
|
||||
<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="oFj-ol-xpL" firstAttribute="bottom" secondItem="4Li-ul-zIi" secondAttribute="bottom" id="G0I-O2-S91"/>
|
||||
<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="10" id="IwX-ja-ZIs"/>
|
||||
<constraint firstItem="d9e-Wv-Y5H" firstAttribute="top" secondItem="4Li-ul-zIi" secondAttribute="top" id="JY4-N1-j8e"/>
|
||||
<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="d9e-Wv-Y5H" firstAttribute="centerY" secondItem="pc8-G9-4pJ" secondAttribute="centerY" id="SLv-F7-w5k"/>
|
||||
<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 firstItem="oFj-ol-xpL" firstAttribute="top" secondItem="eQb-0a-76J" secondAttribute="bottom" constant="8" id="abm-cM-PN0"/>
|
||||
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="eQb-0a-76J" secondAttribute="trailing" constant="20" id="b0B-3w-grH"/>
|
||||
<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="f1p-GL-O3o" firstAttribute="leading" secondItem="4Li-ul-zIi" secondAttribute="trailing" constant="20" id="fGd-YS-phP"/>
|
||||
<constraint firstAttribute="centerX" secondItem="t8c-Fx-e5h" secondAttribute="centerX" 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="eQb-0a-76J" firstAttribute="top" secondItem="KEB-eH-x2Y" secondAttribute="bottom" constant="8" id="m2z-1O-ifB"/>
|
||||
<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="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 firstItem="d9e-Wv-Y5H" firstAttribute="width" secondItem="eQb-0a-76J" secondAttribute="width" id="u4p-1B-x5B"/>
|
||||
<constraint firstAttribute="bottom" secondItem="BbV-3h-mmL" secondAttribute="bottom" constant="35" id="ukF-FH-DE8"/>
|
||||
<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="112.5" y="308"/>
|
||||
</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,12 +33,29 @@
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
[self setupMenu];
|
||||
self.aboutWindowController = [[SNTAboutWindowController alloc] init];
|
||||
|
||||
self.configFileWatcher = [[SNTFileWatcher alloc] initWithFilePath:kDefaultConfigFilePath
|
||||
handler:^{
|
||||
[[SNTConfigurator configurator] reloadConfigData];
|
||||
}];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag {
|
||||
self.aboutWindowController = [[SNTAboutWindowController alloc] init];
|
||||
[self.aboutWindowController showWindow:self];
|
||||
return NO;
|
||||
}
|
||||
@@ -45,23 +65,27 @@
|
||||
- (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 = ^{
|
||||
[weakSelf performSelectorInBackground:@selector(attemptReconnection)
|
||||
withObject:nil];
|
||||
[weakSelf attemptReconnection];
|
||||
};
|
||||
self.listener.invalidationHandler = self.listener.rejectedHandler;
|
||||
[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.
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
- (IBAction)fadeIn:(id)sender {
|
||||
[self setAlphaValue:0.f];
|
||||
[self center];
|
||||
[self makeKeyAndOrderFront:sender];
|
||||
[NSAnimationContext beginGrouping];
|
||||
[[NSAnimationContext currentContext] setDuration:0.15f];
|
||||
|
||||
@@ -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(copy) 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, nonatomic) 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, nonatomic) 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,38 @@
|
||||
|
||||
#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];
|
||||
|
||||
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 +62,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 +75,40 @@
|
||||
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 *)shortenedHash {
|
||||
return [self.event.fileSHA256 substringWithRange:NSMakeRange(0, 10)];
|
||||
}
|
||||
|
||||
- (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 +119,33 @@
|
||||
}
|
||||
|
||||
- (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 length] > 0) {
|
||||
message = self.customMessage;
|
||||
} else {
|
||||
return nil;
|
||||
message = [[SNTConfigurator configurator] defaultBlockMessage];
|
||||
if (!message) {
|
||||
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,8 +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>
|
||||
|
||||
|
||||
@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,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,291 +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 "SNTBinaryInfo.h"
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
|
||||
@interface SNTBinaryInfo ()
|
||||
@property NSString *path;
|
||||
@property NSData *fileData;
|
||||
@property NSBundle *bundleRef;
|
||||
@property NSDictionary *infoDict;
|
||||
@end
|
||||
|
||||
@implementation SNTBinaryInfo
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_path = path;
|
||||
|
||||
_fileData = [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:nil];
|
||||
if (!_fileData) return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)SHA1 {
|
||||
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1([self.fileData bytes], (unsigned int)[self.fileData length], sha1);
|
||||
|
||||
// Convert the binary SHA into hex
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha1[i]];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)machoType {
|
||||
if ([self isDylib]) { return @"Dynamic Library"; }
|
||||
if ([self isKext]) { return @"Kernel Extension"; }
|
||||
if ([self isFat]) { return @"Fat Binary"; }
|
||||
if ([self isMachO]) { return @"Thin Binary"; }
|
||||
if ([self isScript]) { return @"Script"; }
|
||||
return @"Unknown (not executable?)";
|
||||
}
|
||||
|
||||
- (NSArray *)architectures {
|
||||
if (![self isMachO]) return nil;
|
||||
|
||||
if ([self isFat]) {
|
||||
NSMutableArray *ret = [[NSMutableArray alloc] init];
|
||||
|
||||
// Retrieve just the fat_header, if possible.
|
||||
NSData *head = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct fat_header))];
|
||||
if (!head) return nil;
|
||||
struct fat_header *fat_header = (struct fat_header *)[head bytes];
|
||||
|
||||
// Get number of architectures in the binary
|
||||
uint32_t narch = NSSwapBigIntToHost(fat_header->nfat_arch);
|
||||
|
||||
// Retrieve just the fat_arch's, make a mutable copy and if necessary swap the bytes
|
||||
NSData *archs = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
|
||||
sizeof(struct fat_arch) * narch)];
|
||||
if (!archs) return nil;
|
||||
struct fat_arch *fat_archs = (struct fat_arch *)[archs bytes];
|
||||
|
||||
// For each arch, get the name of it's architecture
|
||||
for (int i = 0; i < narch; ++i) {
|
||||
[ret addObject:[self nameForCPUType:NSSwapBigIntToHost(fat_archs[i].cputype)]];
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
struct mach_header *hdr = [self firstMachHeader];
|
||||
return @[ [self nameForCPUType:hdr->cputype] ];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isDylib {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (!mach_header) return NO;
|
||||
if (mach_header->filetype == MH_DYLIB ||
|
||||
mach_header->filetype == MH_FVMLIB) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isKext {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (!mach_header) return NO;
|
||||
if (mach_header->filetype == MH_KEXT_BUNDLE) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isMachO {
|
||||
return ([self.fileData length] >= 160 &&
|
||||
([self isMachHeader:(struct mach_header *)[self.fileData bytes]] || [self isFat]));
|
||||
}
|
||||
|
||||
- (BOOL)isFat {
|
||||
return ([self isFatHeader:(struct fat_header *)[self.fileData bytes]]);
|
||||
}
|
||||
|
||||
- (BOOL)isScript {
|
||||
if ([self.fileData length] < 1) return NO;
|
||||
|
||||
char magic[2];
|
||||
[self.fileData getBytes:&magic length:2];
|
||||
|
||||
return (strncmp("#!", magic, 2) == 0);
|
||||
}
|
||||
|
||||
- (BOOL)isExecutable {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (!mach_header) return NO;
|
||||
if (mach_header->filetype == MH_OBJECT ||
|
||||
mach_header->filetype == MH_EXECUTE ||
|
||||
mach_header->filetype == MH_PRELOAD) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
# 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.
|
||||
*/
|
||||
- (NSBundle *)bundle {
|
||||
if (self.bundleRef) return self.bundleRef;
|
||||
|
||||
NSArray *pathComponents = [self.path pathComponents];
|
||||
|
||||
// Check that the full path is at least 4-levels deep:
|
||||
// e.g: /Calendar.app/Contents/MacOS/Calendar
|
||||
if ([pathComponents count] < 4) return nil;
|
||||
|
||||
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 3)];
|
||||
self.bundleRef = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
|
||||
|
||||
// Clear the bundle if it doesn't have a bundle ID
|
||||
if (![self.bundleRef objectForInfoDictionaryKey:@"CFBundleIdentifier"]) self.bundleRef = nil;
|
||||
|
||||
return self.bundleRef;
|
||||
}
|
||||
|
||||
- (NSString *)bundlePath {
|
||||
return [self.bundle bundlePath];
|
||||
}
|
||||
|
||||
- (NSDictionary *)infoPlist {
|
||||
if (self.infoDict) return self.infoDict;
|
||||
|
||||
if ([self bundle]) {
|
||||
self.infoDict = [[self bundle] infoDictionary];
|
||||
return self.infoDict;
|
||||
}
|
||||
|
||||
NSURL *url = [NSURL fileURLWithPath:self.path isDirectory:NO];
|
||||
self.infoDict =
|
||||
(__bridge_transfer NSDictionary*)CFBundleCopyInfoDictionaryForURL((__bridge CFURLRef) url);
|
||||
return self.infoDict;
|
||||
}
|
||||
|
||||
- (NSString *)bundleIdentifier {
|
||||
return [[self infoPlist] objectForKey:@"CFBundleIdentifier"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleName {
|
||||
return [[self infoPlist] objectForKey:@"CFBundleName"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleVersion {
|
||||
return [[self infoPlist] objectForKey:@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleShortVersionString {
|
||||
return [[self infoPlist] objectForKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
# 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.
|
||||
- (struct mach_header *)firstMachHeader {
|
||||
if (![self isMachO]) return NULL;
|
||||
|
||||
struct mach_header *mach_header = (struct mach_header *)[self.fileData bytes];
|
||||
struct fat_header *fat_header = (struct fat_header *)[self.fileData bytes];
|
||||
|
||||
if ([self isFatHeader:fat_header]) {
|
||||
// Get the bytes for the fat_arch
|
||||
NSData *archHdr = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
|
||||
sizeof(struct fat_arch))];
|
||||
if (!archHdr) return nil;
|
||||
struct fat_arch *fat_arch = (struct fat_arch *)[archHdr bytes];
|
||||
|
||||
// Get bytes for first mach_header
|
||||
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(NSSwapBigIntToHost(fat_arch->offset),
|
||||
sizeof(struct mach_header))];
|
||||
if (!machHdr) return nil;
|
||||
mach_header = (struct mach_header *)[machHdr bytes];
|
||||
}
|
||||
|
||||
if ([self isMachHeader:mach_header]) {
|
||||
return mach_header;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- (BOOL)isMachHeader:(struct mach_header *)header {
|
||||
return (header->magic == MH_MAGIC || header->magic == MH_MAGIC_64 ||
|
||||
header->magic == MH_CIGAM || header->magic == MH_CIGAM_64);
|
||||
}
|
||||
|
||||
- (BOOL)isFatHeader:(struct fat_header *)header {
|
||||
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.
|
||||
- (NSData *)safeSubdataWithRange:(NSRange)range {
|
||||
@try {
|
||||
return [self.fileData subdataWithRange:range];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)nameForCPUType:(cpu_type_t)cpuType {
|
||||
switch (cpuType) {
|
||||
case CPU_TYPE_X86:
|
||||
return @"i386";
|
||||
case CPU_TYPE_X86_64:
|
||||
return @"x86-64";
|
||||
case CPU_TYPE_POWERPC:
|
||||
return @"ppc";
|
||||
case CPU_TYPE_POWERPC64:
|
||||
return @"ppc64";
|
||||
default:
|
||||
return @"unknown";
|
||||
}
|
||||
return 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,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.
|
||||
@property(readonly) SecCertificateRef certRef;
|
||||
///
|
||||
/// Access the underlying certificate ref.
|
||||
///
|
||||
@property(readonly, nonatomic) SecCertificateRef certRef;
|
||||
|
||||
/// SHA-1 hash of the certificate data.
|
||||
@property(readonly) NSString *SHA1;
|
||||
///
|
||||
/// SHA-1 hash of the certificate data.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *SHA1;
|
||||
|
||||
/// Certificate data.
|
||||
@property(readonly) NSData *certData;
|
||||
///
|
||||
/// SHA-256 hash of the certificate data.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *SHA256;
|
||||
|
||||
/// Common Name e.g: "Software Signing"
|
||||
@property(readonly) NSString *commonName;
|
||||
///
|
||||
/// Certificate data.
|
||||
///
|
||||
@property(readonly, nonatomic) NSData *certData;
|
||||
|
||||
/// Country Name e.g: "US"
|
||||
@property(readonly) NSString *countryName;
|
||||
///
|
||||
/// Common Name e.g: "Software Signing"
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *commonName;
|
||||
|
||||
/// Organizational Name e.g: "Apple Inc."
|
||||
@property(readonly) NSString *orgName;
|
||||
///
|
||||
/// Country Name e.g: "US"
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *countryName;
|
||||
|
||||
/// Organizational Unit Name e.g: "Apple Software"
|
||||
@property(readonly) NSString *orgUnit;
|
||||
///
|
||||
/// Organizational Name e.g: "Apple Inc."
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *orgName;
|
||||
|
||||
/// Issuer details, same fields as above.
|
||||
@property(readonly) NSString *issuerCommonName;
|
||||
@property(readonly) NSString *issuerCountryName;
|
||||
@property(readonly) NSString *issuerOrgName;
|
||||
@property(readonly) NSString *issuerOrgUnit;
|
||||
///
|
||||
/// Organizational Unit Name e.g: "Apple Software"
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *orgUnit;
|
||||
|
||||
/// Validity Not Before
|
||||
@property(readonly) NSDate *validFrom;
|
||||
///
|
||||
/// Issuer details, same fields as above.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *issuerCommonName;
|
||||
@property(readonly, nonatomic) NSString *issuerCountryName;
|
||||
@property(readonly, nonatomic) NSString *issuerOrgName;
|
||||
@property(readonly, nonatomic) NSString *issuerOrgUnit;
|
||||
|
||||
/// Validity Not After
|
||||
@property(readonly) NSDate *validUntil;
|
||||
///
|
||||
/// Validity Not Before
|
||||
///
|
||||
@property(readonly, nonatomic) NSDate *validFrom;
|
||||
|
||||
///
|
||||
/// Validity Not After
|
||||
///
|
||||
@property(readonly, nonatomic) 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];
|
||||
@@ -79,9 +80,9 @@ static NSString *const kCertDataKey = @"certData";
|
||||
NSData *output = nil;
|
||||
|
||||
if (SecTransformSetAttribute(transform,
|
||||
kSecTransformInputAttributeName,
|
||||
(__bridge CFDataRef)input,
|
||||
NULL)) {
|
||||
kSecTransformInputAttributeName,
|
||||
(__bridge CFDataRef)input,
|
||||
NULL)) {
|
||||
output = CFBridgingRelease(SecTransformExecute(transform, NULL));
|
||||
}
|
||||
if (transform) CFRelease(transform);
|
||||
@@ -125,11 +126,12 @@ static NSString *const kCertDataKey = @"certData";
|
||||
|
||||
#pragma mark Equality & description
|
||||
|
||||
- (BOOL)isEqual:(SNTCertificate *)other {
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (self == other) return YES;
|
||||
if (![other isKindOfClass:[SNTCertificate class]]) return NO;
|
||||
|
||||
return [self.certData isEqual:other.certData];
|
||||
SNTCertificate *o = other;
|
||||
return [self.certData isEqual:o.certData];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
@@ -137,10 +139,8 @@ static NSString *const kCertDataKey = @"certData";
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"/O=%@/OU=%@/CN=%@",
|
||||
self.orgName,
|
||||
self.orgUnit,
|
||||
self.commonName];
|
||||
return
|
||||
[NSString stringWithFormat:@"/O=%@/OU=%@/CN=%@", self.orgName, self.orgUnit, self.commonName];
|
||||
}
|
||||
|
||||
#pragma mark NSSecureCoding
|
||||
@@ -164,9 +164,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 +207,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];
|
||||
@@ -221,15 +226,18 @@ static NSString *const kCertDataKey = @"certData";
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
@catch (NSException *e) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Retrieve the specified date from the certificate's values and convert from a reference date
|
||||
/// to an NSDate object.
|
||||
///
|
||||
/// @param key The identifier for the date: @c kSecOIDX509V1ValiditityNot{Before,After}
|
||||
/// @return An @c NSDate representing the date and time the certificate is valid from or expires.
|
||||
///
|
||||
- (NSDate *)dateForX509Key:(NSString *)key {
|
||||
NSDictionary *curCertVal = [self allCertificateValues][key];
|
||||
NSNumber *value = curCertVal[(__bridge NSString *)kSecPropertyKeyValue];
|
||||
@@ -250,12 +258,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
|
||||
@property(readonly) SNTCertificate *leafCertificate;
|
||||
///
|
||||
/// Returns the leaf certificate that this binary was signed with
|
||||
///
|
||||
@property(readonly, nonatomic) SNTCertificate *leafCertificate;
|
||||
|
||||
/// Returns the on-disk path of this binary.
|
||||
@property(readonly) NSString *binaryPath;
|
||||
///
|
||||
/// Returns the on-disk path of this binary.
|
||||
///
|
||||
@property(readonly, nonatomic) 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.
|
||||
@@ -18,37 +18,40 @@
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
/**
|
||||
* kStaticSigningFlags are the flags used when validating signatures on disk.
|
||||
*
|
||||
* Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
|
||||
* up validation (see below) but does mean images, plists, etc will not be checked and modifying
|
||||
* these will not be considered invalid. To ensure any code inside the binary is still checked,
|
||||
* we check nested code.
|
||||
*
|
||||
* Timings with different flags:
|
||||
* Checking Xcode 5.1.1 bundle:
|
||||
* kSecCSDefaultFlags: 3.895s
|
||||
* kSecCSDoNotValidateResources: 0.013s
|
||||
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
|
||||
*
|
||||
* Checking Google Chrome 36.0.1985.143 bundle:
|
||||
* kSecCSDefaultFlags: 0.529s
|
||||
* kSecCSDoNotValidateResources: 0.032s
|
||||
* kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
|
||||
*/
|
||||
static const SecCSFlags kStaticSigningFlags = kSecCSDoNotValidateResources | kSecCSCheckNestedCode;
|
||||
|
||||
// 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.
|
||||
*/
|
||||
static const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
|
||||
// kSigningFlags are the flags used when validating signatures for running binaries.
|
||||
//
|
||||
// No special flags needed currently.
|
||||
const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
@interface SNTCodesignChecker ()
|
||||
/// Array of @c SNTCertificate's representing the chain of certs this executable was signed with.
|
||||
@property NSMutableArray *certificates;
|
||||
@end
|
||||
|
||||
|
||||
@implementation SNTCodesignChecker {
|
||||
/// Array of @c SNTCertificate's representing the chain of certs this executable was signed with.
|
||||
NSMutableArray *_certificates;
|
||||
}
|
||||
@implementation SNTCodesignChecker
|
||||
|
||||
#pragma mark Init/dealloc
|
||||
|
||||
@@ -81,12 +84,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];
|
||||
for (int i = 0; i < certs.count; ++i) {
|
||||
NSMutableArray *mutableCerts = [[NSMutableArray alloc] initWithCapacity:certs.count];
|
||||
for (NSUInteger i = 0; i < certs.count; ++i) {
|
||||
SecCertificateRef certRef = (__bridge SecCertificateRef)certs[i];
|
||||
SNTCertificate *newCert = [[SNTCertificate alloc] initWithSecCertificateRef:certRef];
|
||||
[_certificates addObject:newCert];
|
||||
[mutableCerts addObject:newCert];
|
||||
}
|
||||
_certificates = [mutableCerts copy];
|
||||
|
||||
_codeRef = codeRef;
|
||||
CFRetain(_codeRef);
|
||||
@@ -99,10 +103,10 @@ const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
SecStaticCodeRef codeRef = NULL;
|
||||
|
||||
// Get SecStaticCodeRef for binary
|
||||
if (SecStaticCodeCreateWithPath((__bridge CFURLRef)[NSURL fileURLWithPath:binaryPath
|
||||
isDirectory:NO],
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
if (SecStaticCodeCreateWithPath(
|
||||
(__bridge CFURLRef)[NSURL fileURLWithPath:binaryPath isDirectory:NO],
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
self = [self initWithSecStaticCodeRef:codeRef];
|
||||
} else {
|
||||
self = nil;
|
||||
@@ -114,12 +118,13 @@ const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
|
||||
- (instancetype)initWithPID:(pid_t)PID {
|
||||
SecCodeRef codeRef = NULL;
|
||||
NSDictionary *attributes = @{(__bridge NSString *)kSecGuestAttributePid: @(PID)};
|
||||
NSDictionary *attributes = @{ (__bridge NSString *)kSecGuestAttributePid : @(PID) };
|
||||
|
||||
if (SecCodeCopyGuestWithAttributes(NULL,
|
||||
(__bridge CFDictionaryRef)attributes,
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
if (SecCodeCopyGuestWithAttributes(
|
||||
NULL,
|
||||
(__bridge CFDictionaryRef)attributes,
|
||||
kSecCSDefaultFlags,
|
||||
&codeRef) == errSecSuccess) {
|
||||
self = [self initWithSecStaticCodeRef:codeRef];
|
||||
} else {
|
||||
self = nil;
|
||||
@@ -164,9 +169,7 @@ const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:@"%@ binary, signed by %@, located at: %@",
|
||||
binarySource,
|
||||
self.leafCertificate.orgName,
|
||||
self.binaryPath];
|
||||
binarySource, self.leafCertificate.orgName, self.binaryPath];
|
||||
}
|
||||
|
||||
#pragma mark Public accessors
|
||||
@@ -177,7 +180,7 @@ const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
|
||||
|
||||
- (NSString *)binaryPath {
|
||||
CFURLRef path;
|
||||
OSStatus status = SecCodeCopyPath(_codeRef, kSecCSDefaultFlags, &path);
|
||||
OSStatus status = SecCodeCopyPath(self.codeRef, kSecCSDefaultFlags, &path);
|
||||
NSURL *pathURL = CFBridgingRelease(path);
|
||||
if (status != errSecSuccess) return nil;
|
||||
return [pathURL path];
|
||||
|
||||
@@ -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,11 +55,18 @@ 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;
|
||||
|
||||
static const char *kKextPath = "/Library/Extensions/santa-driver.kext";
|
||||
static const char *kSantaDPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santad";
|
||||
static const char *kSantaCtlPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santactl";
|
||||
|
||||
#endif // SANTA__COMMON__COMMONENUMS_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.
|
||||
@@ -14,48 +14,146 @@
|
||||
|
||||
#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
|
||||
@property santa_clientmode_t clientMode;
|
||||
/// Default config file path
|
||||
extern NSString * const kDefaultConfigFilePath;
|
||||
|
||||
/// If YES, debug logging is enabled
|
||||
@property(readonly) BOOL debugLogging;
|
||||
#pragma mark - Daemon Settings
|
||||
|
||||
# pragma mark - Sync Settings
|
||||
///
|
||||
/// The operating mode.
|
||||
///
|
||||
@property(nonatomic) santa_clientmode_t clientMode;
|
||||
|
||||
/// The base URL of the sync server
|
||||
@property(readonly) NSURL *syncBaseURL;
|
||||
///
|
||||
/// Whether or not to log all events, even for whitelisted binaries.
|
||||
///
|
||||
@property(nonatomic) BOOL logAllEvents;
|
||||
|
||||
/// The machine owner
|
||||
@property(readonly) NSString *machineOwner;
|
||||
///
|
||||
/// The regex of whitelisted paths. Regexes are specified in ICU format.
|
||||
///
|
||||
/// The regex flags IXSM can be used, though the s (dotall) and m (multiline) flags are
|
||||
/// pointless as a path only ever has a single line.
|
||||
/// If the regex doesn't begin with ^ to match from the beginning of the line, it will be added.
|
||||
///
|
||||
@property(nonatomic) NSRegularExpression *whitelistPathRegex;
|
||||
|
||||
/// If set, this over-rides the default machine ID used for syncing
|
||||
@property(readonly) NSString *machineIDOverride;
|
||||
#pragma mark - GUI Settings
|
||||
|
||||
# pragma mark Server Auth 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, nonatomic) NSURL *moreInfoURL;
|
||||
|
||||
/// 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;
|
||||
///
|
||||
/// 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, nonatomic) NSString *eventDetailURL;
|
||||
|
||||
/// This property is the same as the above but is a file on disk containing the PEM data.
|
||||
@property(readonly) NSString *syncServerAuthRootsFile;
|
||||
///
|
||||
/// Related to the above property, this string represents the text to show on the button.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *eventDetailText;
|
||||
|
||||
# pragma mark Client Auth Settings
|
||||
///
|
||||
/// For any rule that doesn't have a custom message, this setting overrides the message
|
||||
/// text that is display. If unset, a reasonable default is provided.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *defaultBlockMessage;
|
||||
|
||||
/// 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;
|
||||
#pragma mark - Sync Settings
|
||||
|
||||
/// 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;
|
||||
///
|
||||
/// The base URL of the sync server.
|
||||
///
|
||||
@property(readonly, nonatomic) NSURL *syncBaseURL;
|
||||
|
||||
///
|
||||
/// If YES, mid-execution event uploads are skipped.
|
||||
/// This property is never stored on disk.
|
||||
///
|
||||
@property BOOL syncBackOff;
|
||||
|
||||
/// Retrieve the initialized singleton configurator object
|
||||
///
|
||||
/// The machine owner.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *machineOwner;
|
||||
|
||||
///
|
||||
/// If set, this over-rides the default machine ID used for syncing.
|
||||
///
|
||||
@property(readonly, nonatomic) 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.
|
||||
///
|
||||
@property(readonly, nonatomic) NSData *syncServerAuthRootsData;
|
||||
|
||||
///
|
||||
/// This property is the same as the above but is a file on disk containing the PEM data.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *syncServerAuthRootsFile;
|
||||
|
||||
#pragma mark Client Auth Settings
|
||||
|
||||
///
|
||||
/// If set, this contains the location of a PKCS#12 certificate to be used for sync authentication.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *syncClientAuthCertificateFile;
|
||||
|
||||
///
|
||||
/// Contains the password for the pkcs#12 certificate.
|
||||
///
|
||||
@property(readonly, nonatomic) 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, nonatomic) 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.
|
||||
///
|
||||
@property(readonly, nonatomic) NSString *syncClientAuthCertificateIssuer;
|
||||
|
||||
///
|
||||
/// 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,41 @@
|
||||
#import "SNTConfigurator.h"
|
||||
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
|
||||
@interface SNTConfigurator ()
|
||||
@property NSString *configFilePath;
|
||||
@property NSMutableDictionary *configData;
|
||||
|
||||
/// Creating NSRegularExpression objects is not fast, so cache it.
|
||||
@property NSRegularExpression *cachedWhitelistDirRegex;
|
||||
|
||||
/// Array of keys that cannot be changed while santad is running if santad didn't make the change.
|
||||
@property(readonly) NSArray *protectedKeys;
|
||||
@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 kWhitelistRegexKey = @"WhitelistRegex";
|
||||
static NSString * const kLogAllEventsKey = @"LogAllEvents";
|
||||
|
||||
static NSString * const kMoreInfoURLKey = @"MoreInfoURL";
|
||||
static NSString * const kEventDetailURLKey = @"EventDetailURL";
|
||||
static NSString * const kEventDetailTextKey = @"EventDetailText";
|
||||
static NSString * const kDefaultBlockMessage = @"DefaultBlockMessage";
|
||||
|
||||
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,31 +60,109 @@ 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;
|
||||
}
|
||||
|
||||
# pragma mark Singleton retriever
|
||||
#pragma mark Singleton retriever
|
||||
|
||||
+ (instancetype)configurator {
|
||||
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
|
||||
#pragma mark Protected Keys
|
||||
|
||||
- (NSArray *)protectedKeys {
|
||||
return @[ kClientModeKey, kWhitelistRegexKey ];
|
||||
}
|
||||
|
||||
#pragma mark Public Interface
|
||||
|
||||
- (santa_clientmode_t)clientMode {
|
||||
int cm = [self.configData[kClientModeKey] intValue];
|
||||
if (cm > CLIENTMODE_UNKNOWN && cm < CLIENTMODE_MAX) {
|
||||
return (santa_clientmode_t)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];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSRegularExpression *)whitelistPathRegex {
|
||||
if (!self.cachedWhitelistDirRegex && self.configData[kWhitelistRegexKey]) {
|
||||
NSString *re = self.configData[kWhitelistRegexKey];
|
||||
if (![re hasPrefix:@"^"]) re = [@"^" stringByAppendingString:re];
|
||||
self.cachedWhitelistDirRegex = [NSRegularExpression regularExpressionWithPattern:re
|
||||
options:0
|
||||
error:nil];
|
||||
}
|
||||
return self.cachedWhitelistDirRegex;
|
||||
}
|
||||
|
||||
- (void)setWhitelistPathRegex:(NSRegularExpression *)re {
|
||||
if (!re) {
|
||||
[self.configData removeObjectForKey:kWhitelistRegexKey];
|
||||
} else {
|
||||
self.configData[kWhitelistRegexKey] = [re pattern];
|
||||
}
|
||||
self.cachedWhitelistDirRegex = nil;
|
||||
[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];
|
||||
}
|
||||
|
||||
- (NSString *)defaultBlockMessage {
|
||||
return self.configData[kDefaultBlockMessage];
|
||||
}
|
||||
|
||||
- (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 +180,91 @@ 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 length] == 0) {
|
||||
machineId = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
- (void)setClientMode:(santa_clientmode_t)newMode {
|
||||
if (newMode > CLIENTMODE_UNKNOWN && newMode < CLIENTMODE_MAX) {
|
||||
[self reloadConfigData];
|
||||
self.configData[kClientModeKey] = @(newMode);
|
||||
[self saveConfigToDisk];
|
||||
- (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 protected keys behind our back.
|
||||
NSMutableDictionary *configDataMutable = [configData mutableCopy];
|
||||
BOOL changed = NO;
|
||||
for (NSString *key in self.protectedKeys) {
|
||||
if (self.configData[key] && configData[key] &&
|
||||
![self.configData[key] isEqual:configData[key]] && geteuid() == 0) {
|
||||
NSMutableDictionary *configDataMutable = [configData mutableCopy];
|
||||
configDataMutable[key] = self.configData[key];
|
||||
changed = YES;
|
||||
LOGD(@"Ignoring changed configuration key: %@", key);
|
||||
}
|
||||
}
|
||||
self.configData = configDataMutable;
|
||||
if (changed) [self saveConfigToDisk];
|
||||
}
|
||||
|
||||
#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(void);
|
||||
|
||||
@@ -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,8 +16,9 @@
|
||||
|
||||
BOOL DropRootPrivileges() {
|
||||
if (getuid() == 0 || geteuid() == 0 || getgid() == 0 || getegid() == 0) {
|
||||
if (setgid(-2) != 0 || setgroups(0, NULL) != 0 || setegid(-2) != 0 ||
|
||||
setuid(-2) != 0 || seteuid(-2) != 0) {
|
||||
uid_t nobody = (uid_t)-2;
|
||||
if (setgid(nobody) != 0 || setgroups(0, NULL) != 0 || setegid(nobody) != 0 ||
|
||||
setuid(nobody) != 0 || seteuid(nobody) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,4 +28,4 @@ BOOL DropRootPrivileges() {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
138
Source/common/SNTFileInfo.h
Normal file
138
Source/common/SNTFileInfo.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/// 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.
|
||||
/// @param error If an error occurred and nil is returned, this will be a pointer to an NSError
|
||||
/// describing the problem.
|
||||
///
|
||||
- (instancetype)initWithPath:(NSString *)path error:(NSError **)error;
|
||||
|
||||
///
|
||||
/// Convenience initializer.
|
||||
///
|
||||
/// @param path The path to 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
|
||||
382
Source/common/SNTFileInfo.m
Normal file
382
Source/common/SNTFileInfo.m
Normal file
@@ -0,0 +1,382 @@
|
||||
/// 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 "SNTFileInfo.h"
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
@interface SNTFileInfo ()
|
||||
@property NSString *path;
|
||||
@property NSData *fileData;
|
||||
|
||||
// Cached properties
|
||||
@property NSData *firstMachHeaderData;
|
||||
@property NSBundle *bundleRef;
|
||||
@property NSDictionary *infoDict;
|
||||
@property NSArray *architecturesArray;
|
||||
@end
|
||||
|
||||
@implementation SNTFileInfo
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path error:(NSError **)error {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_path = [self resolvePath:path];
|
||||
if (_path.length == 0) {
|
||||
if (error) {
|
||||
NSString *errStr = @"Unable to resolve empty path";
|
||||
if (path) errStr = [@"Unable to resolve path: " stringByAppendingString:path];
|
||||
*error = [NSError errorWithDomain:@"com.google.santa.fileinfo"
|
||||
code:260
|
||||
userInfo:@{ NSLocalizedDescriptionKey: errStr }];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
_fileData = [NSData dataWithContentsOfFile:_path
|
||||
options:NSDataReadingMappedIfSafe
|
||||
error:error];
|
||||
if (_fileData.length == 0) return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path {
|
||||
return [self initWithPath:path error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *)SHA1 {
|
||||
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1(self.fileData.bytes, (unsigned int)self.fileData.length, sha1);
|
||||
|
||||
// Convert the binary SHA into hex
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha1[i]];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)SHA256 {
|
||||
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha256);
|
||||
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha256[i]];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)machoType {
|
||||
if ([self isDylib]) return @"Dynamic Library";
|
||||
if ([self isKext]) return @"Kernel Extension";
|
||||
if ([self isFat]) return @"Fat Binary";
|
||||
if ([self isMachO]) return @"Thin Binary";
|
||||
if ([self isScript]) return @"Script";
|
||||
return @"Unknown (not executable?)";
|
||||
}
|
||||
|
||||
- (NSArray *)architectures {
|
||||
if (!self.architecturesArray) {
|
||||
self.architecturesArray = (NSArray *)[NSNull null];
|
||||
|
||||
if ([self isFat]) {
|
||||
NSMutableArray *ret = [[NSMutableArray alloc] init];
|
||||
|
||||
// Retrieve just the fat_header, if possible.
|
||||
NSData *head = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct fat_header))];
|
||||
if (!head) return nil;
|
||||
struct fat_header *fat_header = (struct fat_header *)[head bytes];
|
||||
|
||||
// Get number of architectures in the binary
|
||||
uint32_t narch = NSSwapBigIntToHost(fat_header->nfat_arch);
|
||||
|
||||
// Retrieve just the fat_arch's, make a mutable copy and if necessary swap the bytes
|
||||
NSData *archs = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
|
||||
sizeof(struct fat_arch) * narch)];
|
||||
if (!archs) return nil;
|
||||
struct fat_arch *fat_archs = (struct fat_arch *)[archs bytes];
|
||||
|
||||
// For each arch, get the name of its architecture
|
||||
for (uint32_t i = 0; i < narch; ++i) {
|
||||
cpu_type_t cpu = (cpu_type_t)NSSwapBigIntToHost((unsigned int)fat_archs[i].cputype);
|
||||
[ret addObject:[self nameForCPUType:cpu]];
|
||||
}
|
||||
|
||||
self.architecturesArray = ret;
|
||||
} else if ([self firstMachHeader]) {
|
||||
struct mach_header *hdr = [self firstMachHeader];
|
||||
self.architecturesArray = @[ [self nameForCPUType:hdr->cputype] ];
|
||||
}
|
||||
}
|
||||
|
||||
return self.architecturesArray == (NSArray *)[NSNull null] ? nil : self.architecturesArray;
|
||||
}
|
||||
|
||||
- (BOOL)isDylib {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (mach_header && (mach_header->filetype == MH_DYLIB || mach_header->filetype == MH_FVMLIB)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isKext {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (mach_header && mach_header->filetype == MH_KEXT_BUNDLE) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isMachO {
|
||||
return [self firstMachHeader] != nil;
|
||||
}
|
||||
|
||||
- (BOOL)isFat {
|
||||
return ([self isFatHeader:(struct fat_header *)[self.fileData bytes]]);
|
||||
}
|
||||
|
||||
- (BOOL)isScript {
|
||||
char magic[2];
|
||||
[self.fileData getBytes:&magic length:2];
|
||||
|
||||
return (strncmp("#!", magic, 2) == 0);
|
||||
}
|
||||
|
||||
- (BOOL)isExecutable {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (!mach_header) return NO;
|
||||
if (mach_header->filetype == MH_OBJECT ||
|
||||
mach_header->filetype == MH_EXECUTE ||
|
||||
mach_header->filetype == MH_PRELOAD) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#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.
|
||||
///
|
||||
- (NSBundle *)bundle {
|
||||
if (!self.bundleRef) {
|
||||
self.bundleRef = (NSBundle *)[NSNull null];
|
||||
|
||||
// Check that the full path is at least 4-levels deep:
|
||||
// e.g: /Calendar.app/Contents/MacOS/Calendar
|
||||
NSArray *pathComponents = [self.path pathComponents];
|
||||
if ([pathComponents count] < 4) return nil;
|
||||
|
||||
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 3)];
|
||||
NSBundle *bndl = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
|
||||
if (bndl && [bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) self.bundleRef = bndl;
|
||||
}
|
||||
return self.bundleRef == (NSBundle *)[NSNull null] ? nil : self.bundleRef;
|
||||
}
|
||||
|
||||
- (NSString *)bundlePath {
|
||||
return [self.bundle bundlePath];
|
||||
}
|
||||
|
||||
- (NSDictionary *)infoPlist {
|
||||
if (!self.infoDict) {
|
||||
self.infoDict = (NSDictionary *)[NSNull null];
|
||||
|
||||
// Binaries with embedded Info.plist aren't in an NSBundle but
|
||||
// CFBundleCopyInfoDictionaryForURL will return the embedded info dict.
|
||||
NSURL *url = [NSURL fileURLWithPath:self.path isDirectory:NO];
|
||||
NSDictionary *infoDict =
|
||||
(__bridge_transfer NSDictionary *)CFBundleCopyInfoDictionaryForURL((__bridge CFURLRef)url);
|
||||
if (infoDict){
|
||||
self.infoDict = infoDict;
|
||||
} else if ([self bundle] && [self.bundle infoDictionary]) {
|
||||
self.infoDict = [self.bundle infoDictionary];
|
||||
}
|
||||
}
|
||||
return self.infoDict == (NSDictionary *)[NSNull null] ? nil : self.infoDict;
|
||||
}
|
||||
|
||||
- (NSString *)bundleIdentifier {
|
||||
return [self.infoPlist objectForKey:@"CFBundleIdentifier"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleName {
|
||||
return [self.infoPlist objectForKey:@"CFBundleName"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleVersion {
|
||||
return [self.infoPlist objectForKey:@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
- (NSString *)bundleShortVersionString {
|
||||
return [self.infoPlist objectForKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
- (NSArray *)downloadURLs {
|
||||
char *path = (char *)[self.path fileSystemRepresentation];
|
||||
size_t size = (size_t)getxattr(path, "com.apple.metadata:kMDItemWhereFroms", NULL, 0, 0, 0);
|
||||
char *value = malloc(size);
|
||||
if (!value) return nil;
|
||||
|
||||
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.
|
||||
///
|
||||
- (struct mach_header *)firstMachHeader {
|
||||
if (!self.firstMachHeaderData) {
|
||||
self.firstMachHeaderData = (NSData *)[NSNull null];
|
||||
|
||||
if ([self isFatHeader:(struct fat_header *)[self.fileData bytes]]) {
|
||||
// Get the bytes for the fat_arch
|
||||
NSData *archHdr = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
|
||||
sizeof(struct fat_arch))];
|
||||
if (!archHdr) return NULL;
|
||||
struct fat_arch *fat_arch = (struct fat_arch *)[archHdr bytes];
|
||||
|
||||
// Get bytes for first mach_header
|
||||
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(NSSwapBigIntToHost(fat_arch->offset),
|
||||
sizeof(struct mach_header))];
|
||||
if (!machHdr || ![self isMachHeader:(struct mach_header *)machHdr.bytes]) return NULL;
|
||||
|
||||
self.firstMachHeaderData = [machHdr copy];
|
||||
} else if ([self isMachHeader:(struct mach_header *)[self.fileData bytes]]) {
|
||||
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct mach_header))];
|
||||
if (!machHdr) return NULL;
|
||||
self.firstMachHeaderData = [machHdr copy];
|
||||
}
|
||||
}
|
||||
return (self.firstMachHeaderData == (NSData *)[NSNull null] ?
|
||||
NULL :
|
||||
(struct mach_header *)self.firstMachHeaderData.bytes);
|
||||
}
|
||||
|
||||
- (BOOL)isMachHeader:(struct mach_header *)header {
|
||||
return (header->magic == MH_MAGIC || header->magic == MH_MAGIC_64 ||
|
||||
header->magic == MH_CIGAM || header->magic == MH_CIGAM_64);
|
||||
}
|
||||
|
||||
- (BOOL)isFatHeader:(struct fat_header *)header {
|
||||
return (header->magic == FAT_MAGIC || header->magic == FAT_CIGAM);
|
||||
}
|
||||
|
||||
///
|
||||
/// 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];
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)nameForCPUType:(cpu_type_t)cpuType {
|
||||
switch (cpuType) {
|
||||
case CPU_TYPE_X86:
|
||||
return @"i386";
|
||||
case CPU_TYPE_X86_64:
|
||||
return @"x86-64";
|
||||
case CPU_TYPE_POWERPC:
|
||||
return @"ppc";
|
||||
case CPU_TYPE_POWERPC64:
|
||||
return @"ppc64";
|
||||
default:
|
||||
return @"unknown";
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)resolvePath:(NSString *)path {
|
||||
// Convert to absolute, standardized path
|
||||
path = [path stringByResolvingSymlinksInPath];
|
||||
if (![path isAbsolutePath]) {
|
||||
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
path = [cwd stringByAppendingPathComponent:path];
|
||||
}
|
||||
path = [path stringByStandardizingPath];
|
||||
|
||||
// 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"];
|
||||
return [path stringByAppendingPathComponent:d[@"CFBundleExecutable"]];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
34
Source/common/SNTFileWatcher.h
Normal file
34
Source/common/SNTFileWatcher.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
///
|
||||
/// Simple file watching class using dispatch sources. Will automatically
|
||||
/// reload the watch if the file is deleted. Will continue watching for
|
||||
/// events until deallocated.
|
||||
///
|
||||
@interface SNTFileWatcher : NSObject
|
||||
|
||||
///
|
||||
/// Designated initializer
|
||||
/// Initializes the watcher and begins watching for modifications.
|
||||
///
|
||||
/// @param filePath the file to watch.
|
||||
/// @param handler the handler to call when changes happen.
|
||||
///
|
||||
/// @note Shortly after the file has been opened and monitoring has begun, the provided handler
|
||||
/// will be called.
|
||||
///
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath handler:(void (^)(void))handler;
|
||||
|
||||
@end
|
||||
101
Source/common/SNTFileWatcher.m
Normal file
101
Source/common/SNTFileWatcher.m
Normal file
@@ -0,0 +1,101 @@
|
||||
/// 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);
|
||||
}
|
||||
|
||||
const char *filePathCString = [weakSelf.filePath fileSystemRepresentation];
|
||||
while ((fd = open(filePathCString, 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,17 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
///
|
||||
/// Common defines between kernel <-> userspace
|
||||
///
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#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_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 +31,6 @@
|
||||
// List of methods supported by the driver.
|
||||
enum SantaDriverMethods {
|
||||
kSantaUserClientOpen,
|
||||
kSantaUserClientClose,
|
||||
kSantaUserClientAllowBinary,
|
||||
kSantaUserClientDenyBinary,
|
||||
kSantaUserClientClearCache,
|
||||
@@ -51,21 +51,29 @@ typedef enum {
|
||||
ACTION_RESPOND_CHECKBW_ALLOW = 11,
|
||||
ACTION_RESPOND_CHECKBW_DENY = 12,
|
||||
|
||||
// NOTIFY
|
||||
ACTION_NOTIFY_EXEC_ALLOW_NODAEMON = 30,
|
||||
ACTION_NOTIFY_EXEC_ALLOW_CACHED = 31,
|
||||
ACTION_NOTIFY_EXEC_DENY_CACHED = 32,
|
||||
|
||||
// SHUTDOWN
|
||||
ACTION_REQUEST_SHUTDOWN = 60,
|
||||
ACTION_REQUEST_SHUTDOWN = 90,
|
||||
|
||||
// ERROR
|
||||
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];
|
||||
char path[MAX_PATH_LEN];
|
||||
uint64_t vnode_id;
|
||||
pid_t ppid;
|
||||
char path[MAXPATHLEN];
|
||||
} 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,18 +37,22 @@
|
||||
#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.
|
||||
void logMessage(int level, FILE *destination, NSString *format, ...);
|
||||
///
|
||||
/// Logging function.
|
||||
/// @param level one of the levels defined above
|
||||
/// @param destination a FILE, generally stdout/stderr. If the file is closed, the log
|
||||
/// will instead be sent to syslog.
|
||||
/// @param format the printf style format string
|
||||
/// @param ... the arguments to format.
|
||||
///
|
||||
void logMessage(int level, FILE *destination, NSString *format, ...)
|
||||
__attribute__((format(__NSString__, 3, 4)));
|
||||
|
||||
/// Simple logging macros
|
||||
#define LOGD(logFormat, ...) logMessage(LOG_LEVEL_DEBUG, stdout, logFormat, ##__VA_ARGS__);
|
||||
#define LOGI(logFormat, ...) logMessage(LOG_LEVEL_INFO, stdout, logFormat, ##__VA_ARGS__);
|
||||
#define LOGW(logFormat, ...) logMessage(LOG_LEVEL_WARN, stderr, logFormat, ##__VA_ARGS__);
|
||||
#define LOGE(logFormat, ...) logMessage(LOG_LEVEL_ERROR, stderr, logFormat, ##__VA_ARGS__);
|
||||
#define LOGD(logFormat, ...) logMessage(LOG_LEVEL_DEBUG, stdout, logFormat, ##__VA_ARGS__)
|
||||
#define LOGI(logFormat, ...) logMessage(LOG_LEVEL_INFO, stdout, logFormat, ##__VA_ARGS__)
|
||||
#define LOGW(logFormat, ...) logMessage(LOG_LEVEL_WARN, stderr, logFormat, ##__VA_ARGS__)
|
||||
#define LOGE(logFormat, ...) logMessage(LOG_LEVEL_ERROR, stderr, logFormat, ##__VA_ARGS__)
|
||||
|
||||
#endif // KERNEL
|
||||
|
||||
|
||||
@@ -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,30 +14,32 @@
|
||||
|
||||
#import "SNTLogging.h"
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import <sys/syslog.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
static int logLevel = LOG_LEVEL_DEBUG; // default to info
|
||||
static int logLevel = LOG_LEVEL_DEBUG;
|
||||
#else
|
||||
static int logLevel = LOG_LEVEL_INFO;
|
||||
static int logLevel = LOG_LEVEL_INFO; // default to info
|
||||
#endif
|
||||
|
||||
void logMessage(int level, FILE *destination, NSString *format, ...) {
|
||||
static NSDateFormatter *dateFormatter;
|
||||
static BOOL useSyslog = NO;
|
||||
static NSString *binaryName;
|
||||
static dispatch_once_t pred;
|
||||
|
||||
dispatch_once(&pred, ^{
|
||||
dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
|
||||
[dateFormatter setDateFormat:@"YYYY-MM-dd HH:mm:ss.SSS'Z"];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// If requested, redirect output to syslog.
|
||||
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--syslog"] ||
|
||||
[binaryName isEqual:@"santad"]) {
|
||||
useSyslog = YES;
|
||||
}
|
||||
});
|
||||
|
||||
if (logLevel < level) return;
|
||||
@@ -47,19 +49,18 @@ void logMessage(int level, FILE *destination, NSString *format, ...) {
|
||||
NSString *s = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
va_end(args);
|
||||
|
||||
// Only prepend timestamp, severity and binary name if stdout is not a TTY
|
||||
if (isatty(fileno(destination))) {
|
||||
fprintf(destination, "%s\n", [s UTF8String]);
|
||||
} else {
|
||||
if (useSyslog) {
|
||||
NSString *levelName;
|
||||
int syslogLevel = LOG_DEBUG;
|
||||
switch (level) {
|
||||
case LOG_LEVEL_ERROR: levelName = @"E"; break;
|
||||
case LOG_LEVEL_WARN: levelName = @"W"; break;
|
||||
case LOG_LEVEL_INFO: levelName = @"I"; break;
|
||||
case LOG_LEVEL_DEBUG: levelName = @"D"; break;
|
||||
case LOG_LEVEL_ERROR: levelName = @"E"; syslogLevel = LOG_ERR; break;
|
||||
case LOG_LEVEL_WARN: levelName = @"W"; syslogLevel = LOG_WARNING; break;
|
||||
case LOG_LEVEL_INFO: levelName = @"I"; syslogLevel = LOG_INFO; break;
|
||||
case LOG_LEVEL_DEBUG: levelName = @"D"; syslogLevel = LOG_DEBUG; break;
|
||||
}
|
||||
|
||||
fprintf(destination, "%s\n", [[NSString stringWithFormat:@"[%@] %@ %@: %@",
|
||||
[dateFormatter stringFromDate:[NSDate date]], levelName, binaryName, s] UTF8String]);
|
||||
syslog(syslogLevel, "%s\n",
|
||||
[[NSString stringWithFormat:@"%@ %@: %@", levelName, binaryName, s] UTF8String]);
|
||||
} else {
|
||||
fprintf(destination, "%s\n", [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(copy) 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
|
||||
@property NSString *customMsg;
|
||||
///
|
||||
/// A custom message that will be displayed if this rule blocks a binary from executing
|
||||
///
|
||||
@property(copy) 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,32 @@ static NSString *const kCustomMessageKey = @"custommsg";
|
||||
|
||||
#pragma mark NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding { return YES; }
|
||||
#define ENCODE(obj, key) if (obj) [coder encodeObject:obj forKey:key]
|
||||
#define DECODE(cls, key) [decoder decodeObjectOfClass:[cls class] 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
|
||||
#undef DECODE
|
||||
#undef ENCODE
|
||||
|
||||
@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,90 @@
|
||||
|
||||
#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;
|
||||
|
||||
///
|
||||
/// The name of the parent process.
|
||||
///
|
||||
@property NSString *parentName;
|
||||
|
||||
@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,89 +14,89 @@
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
#import "SNTCertificate.h"
|
||||
|
||||
@implementation SNTStoredEvent
|
||||
|
||||
+ (BOOL)supportsSecureCoding { return YES; }
|
||||
#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");
|
||||
ENCODE(self.parentName, @"parentName");
|
||||
|
||||
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 = (santa_eventstate_t)[DECODE(NSNumber, @"decision") intValue];
|
||||
_pid = DECODE(NSNumber, @"pid");
|
||||
_ppid = DECODE(NSNumber, @"ppid");
|
||||
_parentName = DECODE(NSString, @"parentName");
|
||||
|
||||
_loggedInUsers = DECODEARRAY(NSString, @"loggedInUsers");
|
||||
_currentSessions = DECODEARRAY(NSString, @"currentSessions");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(SNTStoredEvent *)other {
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (other == self) return YES;
|
||||
if (![other isKindOfClass:[SNTStoredEvent class]]) return NO;
|
||||
return ([self.fileSHA1 isEqual:other.fileSHA1] &&
|
||||
[self.idx isEqual:other.idx]);
|
||||
SNTStoredEvent *o;
|
||||
return ([self.fileSHA256 isEqual:o.fileSHA256] && [self.idx isEqual:o.idx]);
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
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.
|
||||
@@ -21,14 +21,11 @@
|
||||
kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!platformExpert) return nil;
|
||||
|
||||
NSString *serial = CFBridgingRelease(
|
||||
IORegistryEntryCreateCFProperty(platformExpert,
|
||||
CFSTR(kIOPlatformSerialNumberKey),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
|
||||
NSString *serial = CFBridgingRelease(IORegistryEntryCreateCFProperty(
|
||||
platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0));
|
||||
|
||||
IOObjectRelease(platformExpert);
|
||||
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
@@ -37,10 +34,8 @@
|
||||
kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!platformExpert) return nil;
|
||||
|
||||
NSString *uuid = CFBridgingRelease(
|
||||
IORegistryEntryCreateCFProperty(platformExpert,
|
||||
CFSTR(kIOPlatformUUIDKey),
|
||||
kCFAllocatorDefault, 0));
|
||||
NSString *uuid = CFBridgingRelease(IORegistryEntryCreateCFProperty(
|
||||
platformExpert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0));
|
||||
|
||||
IOObjectRelease(platformExpert);
|
||||
|
||||
@@ -60,14 +55,16 @@
|
||||
}
|
||||
|
||||
+ (NSString *)longHostname {
|
||||
return [[NSHost currentHost] name];
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
gethostname(hostname, (int)sizeof(hostname));
|
||||
return @(hostname);
|
||||
}
|
||||
|
||||
# pragma mark - Internal
|
||||
#pragma mark - Internal
|
||||
|
||||
+ (NSDictionary *)_systemVersionDictionary {
|
||||
return [NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
return [NSDictionary
|
||||
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
}
|
||||
|
||||
@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,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.
|
||||
@property(readonly) id remoteObjectProxy;
|
||||
///
|
||||
/// 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, nonatomic) 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
|
||||
@@ -51,8 +59,7 @@
|
||||
if (self) {
|
||||
Protocol *validatorProtocol = @protocol(XPCConnectionValidityRequest);
|
||||
_validatorInterface = [NSXPCInterface interfaceWithProtocol:validatorProtocol];
|
||||
_currentConnection = [[NSXPCConnection alloc] initWithMachServiceName:name
|
||||
options:options];
|
||||
_currentConnection = [[NSXPCConnection alloc] initWithMachServiceName:name options:options];
|
||||
|
||||
if (!_validatorInterface || !_currentConnection) return nil;
|
||||
}
|
||||
@@ -67,27 +74,26 @@
|
||||
#pragma mark Connection set-up
|
||||
|
||||
- (void)resume {
|
||||
if (_listenerObject) {
|
||||
if (self.listenerObject) {
|
||||
// A new listener doesn't do anything until a client connects.
|
||||
self.listenerObject.delegate = self;
|
||||
[self.listenerObject resume];
|
||||
} else {
|
||||
// A new client begins the validation process.
|
||||
NSXPCConnection *connection = _currentConnection;
|
||||
NSXPCConnection *connection = self.currentConnection;
|
||||
|
||||
connection.remoteObjectInterface = _validatorInterface;
|
||||
connection.remoteObjectInterface = self.validatorInterface;
|
||||
|
||||
connection.invalidationHandler = ^{
|
||||
[self invokeInvalidationHandler];
|
||||
self.currentConnection = nil;
|
||||
};
|
||||
|
||||
connection.interruptionHandler = ^{
|
||||
[self.currentConnection invalidate];
|
||||
};
|
||||
connection.interruptionHandler = ^{ [self.currentConnection invalidate]; };
|
||||
|
||||
[connection resume];
|
||||
|
||||
__block BOOL verificationComplete = NO;
|
||||
[[connection remoteObjectProxy] isConnectionValidWithBlock:^void(BOOL response) {
|
||||
pid_t pid = self.currentConnection.processIdentifier;
|
||||
|
||||
@@ -101,12 +107,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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +130,7 @@
|
||||
if (self.currentConnection) return NO;
|
||||
|
||||
connection.exportedObject = self;
|
||||
connection.exportedInterface = _validatorInterface;
|
||||
connection.exportedInterface = self.validatorInterface;
|
||||
|
||||
connection.invalidationHandler = ^{
|
||||
[self invokeInvalidationHandler];
|
||||
@@ -152,11 +166,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 +208,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,36 +17,50 @@
|
||||
@class SNTRule;
|
||||
@class SNTStoredEvent;
|
||||
|
||||
/// Protocol implemented by santad and utilized by santactl
|
||||
///
|
||||
/// Protocol implemented by santad and utilized by santactl
|
||||
///
|
||||
@protocol SNTDaemonControlXPC
|
||||
|
||||
/// Kernel ops
|
||||
- (void)cacheCount:(void (^)(uint64_t))reply;
|
||||
///
|
||||
/// Kernel ops
|
||||
///
|
||||
- (void)cacheCount:(void (^)(int64_t))reply;
|
||||
- (void)flushCache:(void (^)(BOOL))reply;
|
||||
|
||||
/// 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;
|
||||
///
|
||||
/// Database ops
|
||||
///
|
||||
- (void)databaseRuleCounts:(void (^)(int64_t binary, int64_t certificate))reply;
|
||||
- (void)databaseRuleAddRule:(SNTRule *)rule cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
|
||||
- (void)databaseRuleAddRules:(NSArray *)rules cleanSlate:(BOOL)cleanSlate reply:(void (^)())reply;
|
||||
|
||||
- (void)databaseEventCount:(void (^)(uint64_t count))reply;
|
||||
- (void)databaseEventForSHA1:(NSString *)sha1 withReply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventCount:(void (^)(int64_t count))reply;
|
||||
- (void)databaseEventForSHA256:(NSString *)sha256 reply:(void (^)(SNTStoredEvent *))reply;
|
||||
- (void)databaseEventsPending:(void (^)(NSArray *events))reply;
|
||||
- (void)databaseRemoveEventsWithIDs:(NSArray *)ids;
|
||||
|
||||
/// Misc ops
|
||||
///
|
||||
/// Config ops
|
||||
///
|
||||
- (void)clientMode:(void (^)(santa_clientmode_t))reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode withReply:(void (^)())reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode reply:(void (^)())reply;
|
||||
- (void)setNextSyncInterval:(uint64_t)seconds reply:(void (^)())reply;
|
||||
- (void)setWhitelistPathRegex:(NSString *)pattern reply:(void (^)())reply;
|
||||
|
||||
@end
|
||||
|
||||
@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.
|
||||
@@ -32,7 +32,7 @@
|
||||
ofReply:YES];
|
||||
|
||||
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTRule class], nil]
|
||||
forSelector:@selector(databaseRuleAddRules:withReply:)
|
||||
forSelector:@selector(databaseRuleAddRules:cleanSlate:reply:)
|
||||
argumentIndex:0
|
||||
ofReply:NO];
|
||||
|
||||
|
||||
@@ -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,138 @@ OSDefineMetaClassAndStructors(SantaDecisionManager, OSObject);
|
||||
|
||||
#pragma mark Object Lifecycle
|
||||
|
||||
SantaDecisionManager *SantaDecisionManager::WithQueueAndPID(
|
||||
IOSharedDataQueue *queue, pid_t pid) {
|
||||
SantaDecisionManager *me = new SantaDecisionManager;
|
||||
|
||||
if (me && !me->InitWithQueueAndPID(queue, pid)) {
|
||||
me->free();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::InitWithQueueAndPID(
|
||||
IOSharedDataQueue *queue, pid_t pid) {
|
||||
bool SantaDecisionManager::init() {
|
||||
if (!super::init()) return false;
|
||||
|
||||
if (!pid) return false;
|
||||
if (!queue) return false;
|
||||
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());
|
||||
|
||||
listener_invocations_ = 0;
|
||||
dataqueue_ = queue;
|
||||
owning_pid_ = pid;
|
||||
owning_proc_ = proc_find(pid);
|
||||
cached_decisions_ = OSDictionary::withCapacity(1000);
|
||||
|
||||
if (!(dataqueue_lock_ = IORWLockAlloc())) return FALSE;
|
||||
if (!(cached_decisions_lock_ = IORWLockAlloc())) return FALSE;
|
||||
if (!(cached_decisions_ = OSDictionary::withCapacity(1000))) return FALSE;
|
||||
dataqueue_ = IOSharedDataQueue::withEntries(kMaxQueueEvents,
|
||||
sizeof(santa_message_t));
|
||||
if (!dataqueue_) return kIOReturnNoMemory;
|
||||
|
||||
return TRUE;
|
||||
client_pid_ = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SantaDecisionManager::free() {
|
||||
proc_rele(owning_proc_);
|
||||
|
||||
if (cached_decisions_) {
|
||||
cached_decisions_->release();
|
||||
cached_decisions_ = NULL;
|
||||
}
|
||||
OSSafeReleaseNULL(dataqueue_);
|
||||
OSSafeReleaseNULL(cached_decisions_);
|
||||
|
||||
if (cached_decisions_lock_) {
|
||||
IORWLockFree(cached_decisions_lock_);
|
||||
lck_rw_free(cached_decisions_lock_, sdm_lock_grp_);
|
||||
cached_decisions_lock_ = NULL;
|
||||
}
|
||||
|
||||
if (dataqueue_lock_) {
|
||||
IORWLockFree(dataqueue_lock_);
|
||||
lck_mtx_free(dataqueue_lock_, sdm_lock_grp_);
|
||||
dataqueue_lock_ = NULL;
|
||||
}
|
||||
|
||||
if (sdm_lock_grp_) {
|
||||
lck_grp_free(sdm_lock_grp_);
|
||||
sdm_lock_grp_ = NULL;
|
||||
}
|
||||
|
||||
super::free();
|
||||
}
|
||||
|
||||
# pragma mark Cache Management
|
||||
#pragma mark Client Management
|
||||
|
||||
bool SantaDecisionManager::AddToCache(
|
||||
void SantaDecisionManager::ConnectClient(mach_port_t port, pid_t pid) {
|
||||
if (!pid) return;
|
||||
|
||||
// Any decisions made while the daemon wasn't
|
||||
// connected should be cleared
|
||||
ClearCache();
|
||||
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
dataqueue_->setNotificationPort(port);
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
|
||||
client_pid_ = pid;
|
||||
|
||||
failed_queue_requests_ = 0;
|
||||
}
|
||||
|
||||
void SantaDecisionManager::DisconnectClient(bool itDied) {
|
||||
if (client_pid_ < 1) return;
|
||||
|
||||
client_pid_ = -1;
|
||||
|
||||
// Ask santad to shutdown, in case it's running.
|
||||
if (!itDied) {
|
||||
santa_message_t message = {.action = ACTION_REQUEST_SHUTDOWN};
|
||||
PostToQueue(message);
|
||||
dataqueue_->setNotificationPort(NULL);
|
||||
} else {
|
||||
// If the client died, reset the data queue so when it reconnects
|
||||
// it doesn't get swamped straight away.
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
dataqueue_->release();
|
||||
dataqueue_ = IOSharedDataQueue::withEntries(kMaxQueueEvents,
|
||||
sizeof(santa_message_t));
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::ClientConnected() {
|
||||
return client_pid_ > 0;
|
||||
}
|
||||
|
||||
IOMemoryDescriptor *SantaDecisionManager::GetMemoryDescriptor() {
|
||||
return dataqueue_->getMemoryDescriptor();
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
fileop_listener_ = kauth_listen_scope(KAUTH_SCOPE_FILEOP,
|
||||
fileop_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
if (!fileop_listener_) return kIOReturnInternalError;
|
||||
|
||||
LOGD("Listeners started.");
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
kern_return_t SantaDecisionManager::StopListener() {
|
||||
kauth_unlisten_scope(vnode_listener_);
|
||||
vnode_listener_ = NULL;
|
||||
|
||||
kauth_unlisten_scope(fileop_listener_);
|
||||
fileop_listener_ = NULL;
|
||||
|
||||
// Wait for any active invocations to finish before returning
|
||||
do {
|
||||
IOSleep(5);
|
||||
} while (listener_invocations_);
|
||||
|
||||
// Delete any cached decisions
|
||||
ClearCache();
|
||||
|
||||
LOGD("Listeners 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
|
||||
@@ -83,39 +158,40 @@ bool SantaDecisionManager::AddToCache(
|
||||
// sufficiently large and a kMaxAllowCacheTimeMilliseconds set
|
||||
// sufficiently low, this should only ever occur if someone is purposefully
|
||||
// trying to make the cache grow.
|
||||
LOGD("Cache too large, flushing.");
|
||||
LOGI("Cache too large, flushing.");
|
||||
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));
|
||||
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_);
|
||||
if (!lck_rw_lock_shared_to_exclusive(cached_decisions_lock_)) {
|
||||
// shared_to_exclusive will return false if a previous reader upgraded
|
||||
// and if that happens the lock will have been unlocked. If that happens,
|
||||
// which is rare, relock exclusively.
|
||||
lck_rw_lock_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 +200,27 @@ 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_);
|
||||
}
|
||||
|
||||
#pragma mark Decision Fetching
|
||||
|
||||
santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
santa_action_t result = ACTION_UNSET;
|
||||
uint64_t decision_time = 0;
|
||||
|
||||
IORWLockRead(cached_decisions_lock_);
|
||||
SantaMessage *cached_decision = OSDynamicCast(
|
||||
SantaMessage, cached_decisions_->getObject(identifier));
|
||||
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 +238,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;
|
||||
}
|
||||
}
|
||||
@@ -171,159 +248,100 @@ santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
return result;
|
||||
}
|
||||
|
||||
# pragma mark Queue Management
|
||||
|
||||
bool SantaDecisionManager::PostToQueue(santa_message_t message) {
|
||||
IORWLockWrite(dataqueue_lock_);
|
||||
bool kr = dataqueue_->enqueue(&message, sizeof(message));
|
||||
IORWLockUnlock(dataqueue_lock_);
|
||||
return kr;
|
||||
}
|
||||
|
||||
santa_action_t SantaDecisionManager::FetchDecision(
|
||||
const kauth_cred_t credential,
|
||||
const vfs_context_t vfs_context,
|
||||
const vnode_t vnode) {
|
||||
santa_action_t SantaDecisionManager::GetFromDaemon(
|
||||
const santa_message_t message, const char *vnode_id_str) {
|
||||
santa_action_t return_action = ACTION_UNSET;
|
||||
|
||||
// Fetch Vnode ID & string
|
||||
uint64_t vnode_id = GetVnodeIDForVnode(vfs_context, vnode);
|
||||
char vnode_id_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_id_str, MAX_VNODE_ID_STR, "%llu", vnode_id);
|
||||
|
||||
// Check to see if item is in cache
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
|
||||
// If item wasn't in cache, fetch decision from daemon.
|
||||
if (return_action == ACTION_UNSET) {
|
||||
// Add pending request to cache
|
||||
// Wait for the daemon to respond or die.
|
||||
do {
|
||||
// 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;
|
||||
if (vn_getpath(vnode, path, &name_len) != 0) {
|
||||
path[0] = '\0';
|
||||
}
|
||||
|
||||
// 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.action = ACTION_REQUEST_CHECKBW;
|
||||
message.vnode_id = vnode_id;
|
||||
|
||||
// Wait for the daemon to respond or die.
|
||||
do {
|
||||
// Send request to daemon...
|
||||
if (!PostToQueue(message)) {
|
||||
LOGE("Failed to queue request for %s.", path);
|
||||
CacheCheck(vnode_id_str);
|
||||
return ACTION_ERROR;
|
||||
// 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(client_pid_, SIGKILL);
|
||||
}
|
||||
|
||||
// ... and wait for it to respond. If after kRequestLoopSleepMilliseconds
|
||||
// * kMaxRequestLoops it still hasn't responded, send request again.
|
||||
for (int i = 0; i < kMaxRequestLoops; ++i) {
|
||||
IOSleep(kRequestLoopSleepMilliseconds);
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
if (return_action != ACTION_REQUEST_CHECKBW) break;
|
||||
}
|
||||
} while (return_action == ACTION_REQUEST_CHECKBW && proc_exiting(owning_proc_) == 0);
|
||||
|
||||
if (return_action == ACTION_UNSET || return_action == ACTION_ERROR) {
|
||||
LOGE("Daemon process did not respond correctly. Allowing executions "
|
||||
"until it comes back.");
|
||||
LOGE("Failed to queue request for %s.", message.path);
|
||||
CacheCheck(vnode_id_str);
|
||||
return ACTION_ERROR;
|
||||
}
|
||||
|
||||
do {
|
||||
IOSleep(kRequestLoopSleepMilliseconds);
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
} while (return_action == ACTION_REQUEST_CHECKBW && ClientConnected());
|
||||
} while (!CHECKBW_RESPONSE_VALID(return_action) && ClientConnected());
|
||||
|
||||
// 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);
|
||||
return ACTION_ERROR;
|
||||
}
|
||||
|
||||
return return_action;
|
||||
}
|
||||
|
||||
# pragma mark Misc
|
||||
santa_action_t SantaDecisionManager::FetchDecision(
|
||||
const kauth_cred_t cred,
|
||||
const vnode_t vp,
|
||||
const uint64_t vnode_id,
|
||||
const char *vnode_id_str) {
|
||||
santa_action_t return_action = ACTION_UNSET;
|
||||
|
||||
bool SantaDecisionManager::CalculateSHA1ForVnode(const kauth_cred_t credential,
|
||||
const vfs_context_t context,
|
||||
const vnode_t vp,
|
||||
char *out) {
|
||||
out[0] = '\0';
|
||||
// Check to see if item is in cache
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
|
||||
// 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;
|
||||
// If item wasn in cache return it.
|
||||
if CHECKBW_RESPONSE_VALID(return_action) return return_action;
|
||||
|
||||
// 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);
|
||||
// Get path
|
||||
char path[MAXPATHLEN];
|
||||
int name_len = MAXPATHLEN;
|
||||
if (vn_getpath(vp, path, &name_len) != 0) {
|
||||
path[0] = '\0';
|
||||
}
|
||||
|
||||
// Free |readChunk|
|
||||
IOFree(readChunk, chunkSize);
|
||||
// Prepare message to send to daemon.
|
||||
santa_message_t message = {};
|
||||
strlcpy(message.path, path, sizeof(message.path));
|
||||
message.userId = kauth_cred_getuid(cred);
|
||||
message.pid = proc_selfpid();
|
||||
message.ppid = proc_selfppid();
|
||||
message.action = ACTION_REQUEST_CHECKBW;
|
||||
message.vnode_id = vnode_id;
|
||||
|
||||
// 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]);
|
||||
if (ClientConnected()) {
|
||||
return GetFromDaemon(message, vnode_id_str);
|
||||
} else {
|
||||
LOGI("Execution request without daemon running: %s", path);
|
||||
message.action = ACTION_NOTIFY_EXEC_ALLOW_NODAEMON;
|
||||
PostToQueue(message);
|
||||
return ACTION_RESPOND_CHECKBW_ALLOW;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t SantaDecisionManager::GetVnodeIDForVnode(const vfs_context_t context,
|
||||
const vnode_t vp) {
|
||||
#pragma mark Misc
|
||||
|
||||
bool SantaDecisionManager::PostToQueue(santa_message_t message) {
|
||||
bool kr = false;
|
||||
lck_mtx_lock(dataqueue_lock_);
|
||||
kr = dataqueue_->enqueue(&message, sizeof(message));
|
||||
lck_mtx_unlock(dataqueue_lock_);
|
||||
return kr;
|
||||
}
|
||||
|
||||
uint64_t SantaDecisionManager::GetVnodeIDForVnode(
|
||||
const vfs_context_t ctx, const vnode_t vp) {
|
||||
struct vnode_attr vap;
|
||||
VATTR_INIT(&vap);
|
||||
VATTR_WANTED(&vap, va_fileid);
|
||||
vnode_getattr(vp, &vap, context);
|
||||
vnode_getattr(vp, &vap, ctx);
|
||||
return vap.va_fileid;
|
||||
}
|
||||
|
||||
@@ -334,11 +352,7 @@ uint64_t SantaDecisionManager::GetCurrentUptime() {
|
||||
return (uint64_t)((sec * 1000000) + usec);
|
||||
}
|
||||
|
||||
# pragma mark Invocation Tracking & PID comparison
|
||||
|
||||
SInt32 SantaDecisionManager::GetListenerInvocations() {
|
||||
return listener_invocations_;
|
||||
}
|
||||
#pragma mark Invocation Tracking & PID comparison
|
||||
|
||||
void SantaDecisionManager::IncrementListenerInvocations() {
|
||||
OSIncrementAtomic(&listener_invocations_);
|
||||
@@ -348,164 +362,94 @@ void SantaDecisionManager::DecrementListenerInvocations() {
|
||||
OSDecrementAtomic(&listener_invocations_);
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::MatchesOwningPID(const pid_t other_pid) {
|
||||
return (owning_pid_ == other_pid);
|
||||
int SantaDecisionManager::VnodeCallback(const kauth_cred_t cred,
|
||||
const vfs_context_t ctx,
|
||||
const vnode_t vp,
|
||||
int *errno) {
|
||||
// Only operate on regular files (not directories, symlinks, etc.).
|
||||
vtype vt = vnode_vtype(vp);
|
||||
if (vt != VREG) return KAUTH_RESULT_DEFER;
|
||||
|
||||
// Get ID for the vnode and convert it to a string.
|
||||
uint64_t vnode_id = GetVnodeIDForVnode(ctx, vp);
|
||||
char vnode_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_str, MAX_VNODE_ID_STR, "%llu", vnode_id);
|
||||
|
||||
// Fetch decision
|
||||
santa_action_t returnedAction = FetchDecision(cred, vp, vnode_id, vnode_str);
|
||||
|
||||
// If file has dirty blocks, remove from cache and deny. This would usually
|
||||
// be the case if a file has been written to and flushed but not yet
|
||||
// closed.
|
||||
if (vnode_hasdirtyblks(vp)) {
|
||||
CacheCheck(vnode_str);
|
||||
returnedAction = ACTION_RESPOND_CHECKBW_DENY;
|
||||
}
|
||||
|
||||
switch (returnedAction) {
|
||||
case ACTION_RESPOND_CHECKBW_ALLOW:
|
||||
return KAUTH_RESULT_ALLOW;
|
||||
case ACTION_RESPOND_CHECKBW_DENY:
|
||||
*errno = EPERM;
|
||||
return KAUTH_RESULT_DENY;
|
||||
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.
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
# 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;
|
||||
int SantaDecisionManager::FileOpCallback(const vnode_t vp) {
|
||||
vfs_context_t context = vfs_context_create(NULL);
|
||||
char vnode_id_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_id_str, MAX_VNODE_ID_STR, "%llu",
|
||||
GetVnodeIDForVnode(context, vp));
|
||||
CacheCheck(vnode_id_str);
|
||||
vfs_context_rele(context);
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
#undef super
|
||||
|
||||
#pragma mark Kauth Callbacks
|
||||
|
||||
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;
|
||||
extern "C" int fileop_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 (action != KAUTH_FILEOP_CLOSE ||
|
||||
!(arg2 & KAUTH_FILEOP_CLOSE_MODIFIED) ||
|
||||
idata == NULL) {
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
sdm->IncrementListenerInvocations();
|
||||
sdm->FileOpCallback(reinterpret_cast<vnode_t>(arg0));
|
||||
sdm->DecrementListenerInvocations();
|
||||
|
||||
return KAUTH_RESULT_ALLOW;
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
|
||||
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 default action is to defer
|
||||
int returnResult = KAUTH_RESULT_DEFER;
|
||||
|
||||
// Cast arguments to correct types
|
||||
if (idata == NULL) {
|
||||
LOGE("Vnode callback established without valid decision manager.");
|
||||
return returnResult;
|
||||
}
|
||||
SantaDecisionManager *sdm = OSDynamicCast(
|
||||
SantaDecisionManager, reinterpret_cast<OSObject *>(idata));
|
||||
vfs_context_t vfs_context = reinterpret_cast<vfs_context_t>(arg0);
|
||||
vnode_t vnode = reinterpret_cast<vnode_t>(arg1);
|
||||
|
||||
// Only operate on regular files (not directories, symlinks, etc.)
|
||||
vtype vt = vnode_vtype(vnode);
|
||||
if (vt != VREG) return returnResult;
|
||||
|
||||
if (action & KAUTH_VNODE_ACCESS) return returnResult;
|
||||
|
||||
// Filter for only WRITE_DATA actions
|
||||
if (action & KAUTH_VNODE_WRITE_DATA || action & KAUTH_VNODE_APPEND_DATA) {
|
||||
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) {
|
||||
*(reinterpret_cast<int *>(arg3)) = EACCES;
|
||||
return KAUTH_RESULT_DENY;
|
||||
}
|
||||
|
||||
// Otherwise remove from cache
|
||||
sdm->CacheCheck(vnode_id_str);
|
||||
|
||||
return returnResult;
|
||||
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) {
|
||||
if (action & KAUTH_VNODE_ACCESS ||
|
||||
!(action & KAUTH_VNODE_EXECUTE) ||
|
||||
idata == NULL) {
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
// Filter for only EXECUTE actions
|
||||
if (action & KAUTH_VNODE_EXECUTE) {
|
||||
sdm->IncrementListenerInvocations();
|
||||
SantaDecisionManager *sdm =
|
||||
OSDynamicCast(SantaDecisionManager, reinterpret_cast<OSObject *>(idata));
|
||||
|
||||
// Fetch decision
|
||||
santa_action_t returnedAction = sdm->FetchDecision(
|
||||
credential, vfs_context, vnode);
|
||||
|
||||
switch (returnedAction) {
|
||||
case ACTION_RESPOND_CHECKBW_ALLOW:
|
||||
returnResult = KAUTH_RESULT_ALLOW;
|
||||
break;
|
||||
case ACTION_RESPOND_CHECKBW_DENY:
|
||||
*(reinterpret_cast<int *>(arg3)) = EACCES;
|
||||
returnResult = KAUTH_RESULT_DENY;
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
sdm->DecrementListenerInvocations();
|
||||
|
||||
return returnResult;
|
||||
}
|
||||
|
||||
return returnResult;
|
||||
sdm->IncrementListenerInvocations();
|
||||
int result = sdm->VnodeCallback(credential,
|
||||
reinterpret_cast<vfs_context_t>(arg0),
|
||||
reinterpret_cast<vnode_t>(arg1),
|
||||
reinterpret_cast<int *>(arg3));
|
||||
sdm->DecrementListenerInvocations();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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,10 +15,11 @@
|
||||
#ifndef SANTA__SANTA_DRIVER__SANTADECISIONMANAGER_H
|
||||
#define SANTA__SANTA_DRIVER__SANTADECISIONMANAGER_H
|
||||
|
||||
#include <IOKit/IODataQueueShared.h>
|
||||
#include <IOKit/IOLib.h>
|
||||
#include <IOKit/IOMemoryDescriptor.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,130 +28,213 @@
|
||||
#include "SNTKernelCommon.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
const int kMaxRequestLoops = 50;
|
||||
|
||||
/// 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
|
||||
/// 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() override;
|
||||
|
||||
bool InitWithQueueAndPID(IOSharedDataQueue *queue, pid_t pid);
|
||||
void free();
|
||||
/// Called automatically when retain count drops to 0.
|
||||
void free() override;
|
||||
|
||||
// Decision Fetching / Daemon Communication
|
||||
bool PostToQueue(santa_message_t);
|
||||
santa_action_t FetchDecision(const kauth_cred_t credential,
|
||||
const vfs_context_t vfs_context,
|
||||
const vnode_t vnode);
|
||||
/// Called by SantaDriverClient during connection to provide the shared
|
||||
/// dataqueue memory to the client.
|
||||
IOMemoryDescriptor *GetMemoryDescriptor();
|
||||
|
||||
// Hash calculation
|
||||
bool CalculateSHA1ForVnode(const kauth_cred_t credential,
|
||||
const vfs_context_t context,
|
||||
const vnode_t vnode,
|
||||
char *out);
|
||||
/// Called by SantaDriverClient when a client connects, providing the data
|
||||
/// queue used to pass messages and the pid of the client process.
|
||||
void ConnectClient(mach_port_t port, pid_t pid);
|
||||
|
||||
// Vnode ID string
|
||||
uint64_t GetVnodeIDForVnode(const vfs_context_t context, const vnode_t vp);
|
||||
/// Called by SantaDriverClient when a client disconnects
|
||||
void DisconnectClient(bool itDied = false);
|
||||
|
||||
// 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);
|
||||
/// Returns whether a client is currently connected or not.
|
||||
bool ClientConnected();
|
||||
|
||||
// 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
|
||||
uint64_t GetCurrentUptime();
|
||||
|
||||
// Starting and stopping the listener
|
||||
/// Starts the kauth listeners.
|
||||
kern_return_t StartListener();
|
||||
|
||||
/// Stops the kauth listeners. 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 = GetCurrentUptime());
|
||||
|
||||
/// 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();
|
||||
|
||||
/// Increments the count of active vnode callback's pending.
|
||||
void IncrementListenerInvocations();
|
||||
|
||||
/// Decrements the count of active vnode callback's pending.
|
||||
void DecrementListenerInvocations();
|
||||
|
||||
///
|
||||
/// Vnode Callback
|
||||
/// @param cred The kauth credential for this request.
|
||||
/// @param ctx The VFS context for this request.
|
||||
/// @param vp The Vnode for this request.
|
||||
/// @param errno A pointer to return an errno style error.
|
||||
/// @return int A valid KAUTH_RESULT_*.
|
||||
///
|
||||
int VnodeCallback(const kauth_cred_t cred, const vfs_context_t ctx,
|
||||
const vnode_t vp, int *errno);
|
||||
///
|
||||
/// FileOp Callback
|
||||
/// @param vp The Vnode for this request.
|
||||
/// @return int Should always be KAUTH_RESULT_DEFER.
|
||||
///
|
||||
int FileOpCallback(const vnode_t vp);
|
||||
|
||||
protected:
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
const int kRequestLoopSleepMilliseconds = 10;
|
||||
|
||||
///
|
||||
/// Maximum number of entries in the in-kernel cache.
|
||||
///
|
||||
const int kMaxCacheSize = 10000;
|
||||
|
||||
///
|
||||
/// Maximum number of PostToQueue failures to allow.
|
||||
///
|
||||
const int kMaxQueueFailures = 10;
|
||||
|
||||
///
|
||||
/// The maximum number of messages can be kept in
|
||||
/// the IODataQueue at any time.
|
||||
///
|
||||
const int kMaxQueueEvents = 512;
|
||||
|
||||
/// Fetches a response from the cache, first checking to see if the
|
||||
/// entry has expired.
|
||||
santa_action_t GetFromCache(const char *identifier);
|
||||
|
||||
/// Fetches a response from the daemon. Handles both daemon death
|
||||
/// and failure to post messages to the daemon.
|
||||
///
|
||||
/// @param message The message to send to the daemon
|
||||
/// @param identifier The vnode ID string for this request
|
||||
/// @return santa_action_t The response for this request
|
||||
///
|
||||
santa_action_t GetFromDaemon(const santa_message_t message,
|
||||
const char *identifier);
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// @param cred The credential for this request.
|
||||
/// @param vp The Vnode for this request.
|
||||
/// @param vnode_id The ID for this vnode.
|
||||
/// @param vnode_id_str A string representation of the above ID.
|
||||
///
|
||||
santa_action_t FetchDecision(const kauth_cred_t cred,
|
||||
const vnode_t vp,
|
||||
const uint64_t vnode_id,
|
||||
const char *vnode_id_str);
|
||||
|
||||
///
|
||||
/// Posts the requested message to the client data queue.
|
||||
///
|
||||
/// @param message The message to send
|
||||
/// @return bool true if sending was successful.
|
||||
///
|
||||
bool PostToQueue(santa_message_t message);
|
||||
|
||||
///
|
||||
/// Fetches the vnode_id for a given vnode.
|
||||
///
|
||||
/// @param ctx The VFS context to use.
|
||||
/// @param vp The Vnode to get the ID for
|
||||
/// @return uint64_t The Vnode ID as a 64-bit unsigned int.
|
||||
///
|
||||
uint64_t GetVnodeIDForVnode(const vfs_context_t ctx, const vnode_t vp);
|
||||
|
||||
/// Returns the current system uptime in microseconds
|
||||
static uint64_t GetCurrentUptime();
|
||||
|
||||
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_;
|
||||
|
||||
pid_t owning_pid_;
|
||||
proc_t owning_proc_;
|
||||
pid_t client_pid_;
|
||||
|
||||
kauth_listener_t vnode_listener_;
|
||||
kauth_listener_t process_listener_;
|
||||
kauth_listener_t fileop_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 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);
|
||||
|
||||
///
|
||||
/// The kauth callback function for the FileOp scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested
|
||||
/// @param depends on action, usually the vnode ref.
|
||||
/// @param depends on action.
|
||||
/// @param depends on action, usually 0.
|
||||
/// @param depends on action, usually 0.
|
||||
///
|
||||
extern "C" int fileop_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
|
||||
|
||||
#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,14 @@ OSDefineMetaClassAndStructors(com_google_SantaDriver, IOService);
|
||||
bool SantaDriver::start(IOService *provider) {
|
||||
if (!super::start(provider)) return false;
|
||||
|
||||
santaDecisionManager = new SantaDecisionManager;
|
||||
if (!santaDecisionManager->init() ||
|
||||
santaDecisionManager->StartListener() != kIOReturnSuccess) {
|
||||
santaDecisionManager->release();
|
||||
santaDecisionManager = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
registerService();
|
||||
|
||||
LOGI("Loaded, version %s.", OSKextGetCurrentVersionString());
|
||||
@@ -31,7 +39,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,26 @@
|
||||
#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:
|
||||
bool start(IOService *provider);
|
||||
void stop(IOService *provider);
|
||||
/// Called by the kernel when the kext is loaded
|
||||
bool start(IOService *provider) override;
|
||||
|
||||
/// Called by the kernel when the kext is unloaded
|
||||
void stop(IOService *provider) override;
|
||||
|
||||
/// 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) {
|
||||
@@ -36,81 +36,58 @@ bool SantaDriverClient::initWithTask(
|
||||
}
|
||||
|
||||
bool SantaDriverClient::start(IOService *provider) {
|
||||
fProvider = OSDynamicCast(com_google_SantaDriver, provider);
|
||||
myProvider = OSDynamicCast(com_google_SantaDriver, provider);
|
||||
|
||||
if (!fProvider) return false;
|
||||
if (!myProvider) return false;
|
||||
if (!super::start(provider)) return false;
|
||||
|
||||
fSDMLock = IOLockAlloc();
|
||||
decisionManager = myProvider->GetDecisionManager();
|
||||
if (!decisionManager) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SantaDriverClient::stop(IOService *provider) {
|
||||
super::stop(provider);
|
||||
myProvider = NULL;
|
||||
decisionManager = NULL;
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::clientClose() {
|
||||
close();
|
||||
terminate(kIOServiceSynchronous);
|
||||
|
||||
fProvider = NULL;
|
||||
|
||||
return kIOReturnSuccess;
|
||||
decisionManager->DisconnectClient(true);
|
||||
return terminate(kIOServiceSynchronous) ? kIOReturnSuccess : kIOReturnError;
|
||||
}
|
||||
|
||||
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();
|
||||
decisionManager->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);
|
||||
|
||||
LOGI("Client disconnected.");
|
||||
|
||||
fSDM->release();
|
||||
fSDM = NULL;
|
||||
}
|
||||
IOLockUnlock(fSDMLock);
|
||||
|
||||
if (fProvider && fProvider->isOpen(this)) fProvider->close(this);
|
||||
if (myProvider && myProvider->isOpen(this)) myProvider->close(this);
|
||||
|
||||
return super::terminate(options);
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::registerNotificationPort(mach_port_t port,
|
||||
UInt32 type,
|
||||
UInt32 ref) {
|
||||
if ((!fDataQueue) || (port == MACH_PORT_NULL)) return kIOReturnError;
|
||||
#pragma mark Fetching memory and data queue notifications
|
||||
|
||||
fDataQueue->setNotificationPort(port);
|
||||
IOReturn SantaDriverClient::registerNotificationPort(
|
||||
mach_port_t port, UInt32 type, UInt32 ref) {
|
||||
if (port == MACH_PORT_NULL) return kIOReturnError;
|
||||
|
||||
decisionManager->ConnectClient(port, proc_selfpid());
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::clientMemoryForType(UInt32 type,
|
||||
IOOptionBits *options,
|
||||
IOMemoryDescriptor **memory) {
|
||||
*memory = NULL;
|
||||
IOReturn SantaDriverClient::clientMemoryForType(
|
||||
UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory) {
|
||||
if (type != kIODefaultMemoryType) return kIOReturnNoMemory;
|
||||
|
||||
*options = 0;
|
||||
*memory = decisionManager->GetMemoryDescriptor();
|
||||
(*memory)->retain();
|
||||
|
||||
if (type == kIODefaultMemoryType) {
|
||||
if (!fSharedMemory) return kIOReturnNoMemory;
|
||||
fSharedMemory->retain(); // client will decrement this ref
|
||||
*memory = fSharedMemory;
|
||||
|
||||
return fSDM->StartListener();
|
||||
}
|
||||
|
||||
return kIOReturnNoMemory;
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
#pragma mark Callable Methods
|
||||
@@ -118,29 +95,11 @@ IOReturn SantaDriverClient::clientMemoryForType(UInt32 type,
|
||||
IOReturn SantaDriverClient::open() {
|
||||
if (isInactive()) return kIOReturnNotAttached;
|
||||
|
||||
if (!fProvider->open(this)) {
|
||||
if (!myProvider->open(this)) {
|
||||
LOGW("A second client tried to connect.");
|
||||
return kIOReturnExclusiveAccess;
|
||||
}
|
||||
|
||||
fDataQueue = IOSharedDataQueue::withCapacity((sizeof(santa_message_t) +
|
||||
DATA_QUEUE_ENTRY_HEADER_SIZE)
|
||||
* kMaxQueueEvents);
|
||||
if (!fDataQueue) return kIOReturnNoMemory;
|
||||
|
||||
fSharedMemory = fDataQueue->getMemoryDescriptor();
|
||||
if (!fSharedMemory) {
|
||||
fDataQueue->release();
|
||||
fDataQueue = NULL;
|
||||
return kIOReturnVMError;
|
||||
}
|
||||
|
||||
IOLockLock(fSDMLock);
|
||||
fSDM = SantaDecisionManager::WithQueueAndPID(fDataQueue, proc_selfpid());
|
||||
IOLockUnlock(fSDMLock);
|
||||
|
||||
LOGI("Client connected, PID: %d.", proc_selfpid());
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -152,27 +111,10 @@ 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);
|
||||
fSDM->AddToCache(vnode_id_str,
|
||||
ACTION_RESPOND_CHECKBW_ALLOW,
|
||||
fSDM->GetCurrentUptime());
|
||||
decisionManager->AddToCache(vnode_id_str, ACTION_RESPOND_CHECKBW_ALLOW);
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
@@ -189,9 +131,7 @@ IOReturn SantaDriverClient::static_allow_binary(
|
||||
IOReturn SantaDriverClient::deny_binary(const uint64_t vnode_id) {
|
||||
char vnode_id_str[21];
|
||||
snprintf(vnode_id_str, sizeof(vnode_id_str), "%llu", vnode_id);
|
||||
fSDM->AddToCache(vnode_id_str,
|
||||
ACTION_RESPOND_CHECKBW_DENY,
|
||||
fSDM->GetCurrentUptime());
|
||||
decisionManager->AddToCache(vnode_id_str, ACTION_RESPOND_CHECKBW_DENY);
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
@@ -206,7 +146,7 @@ IOReturn SantaDriverClient::static_deny_binary(
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::clear_cache() {
|
||||
fSDM->ClearCache();
|
||||
decisionManager->ClearCache();
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -219,7 +159,7 @@ IOReturn SantaDriverClient::static_clear_cache(
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::cache_count(uint64_t *output) {
|
||||
*output = fSDM->CacheCount();
|
||||
*output = decisionManager->CacheCount();
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -239,8 +179,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 +189,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.
|
||||
@@ -16,10 +16,6 @@
|
||||
#define SANTA__SANTA_DRIVER__SANTADRIVERUSERCLIENT_H
|
||||
|
||||
#include <IOKit/IOUserClient.h>
|
||||
#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>
|
||||
@@ -29,84 +25,96 @@
|
||||
#include "SantaMessage.h"
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
// The maximum number of messages can be kept in the IODataQueue at any time.
|
||||
const int kMaxQueueEvents = 64;
|
||||
|
||||
/// 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
|
||||
/// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/WritingDeviceDriver/WritingDeviceDriver.pdf
|
||||
///
|
||||
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);
|
||||
bool initWithTask(task_t owningTask, void *securityID, UInt32 type);
|
||||
/// Called as part of IOServiceOpen in clients
|
||||
bool initWithTask(task_t owningTask, void *securityID, UInt32 type) override;
|
||||
|
||||
/// Called after initWithTask as part of IOServiceOpen
|
||||
bool start(IOService *provider) override;
|
||||
|
||||
/// Called when this class is stopping
|
||||
void stop(IOService *provider) override;
|
||||
|
||||
/// Called when a client disconnects
|
||||
IOReturn clientClose() override;
|
||||
|
||||
/// Called when the driver is shutting down
|
||||
bool terminate(IOOptionBits options) override;
|
||||
|
||||
/// Called in clients with IOConnectSetNotificationPort
|
||||
IOReturn registerNotificationPort(
|
||||
mach_port_t port, UInt32 type, UInt32 refCon);
|
||||
mach_port_t port, UInt32 type, UInt32 refCon) override;
|
||||
|
||||
/// Called in clients with IOConnectMapMemory
|
||||
IOReturn clientMemoryForType(
|
||||
UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory);
|
||||
UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory) override;
|
||||
|
||||
/// 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);
|
||||
OSObject *target, void *reference) override;
|
||||
|
||||
///
|
||||
/// 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:
|
||||
com_google_SantaDriver *myProvider;
|
||||
SantaDecisionManager *decisionManager;
|
||||
};
|
||||
|
||||
#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.
|
||||
@@ -24,8 +24,8 @@ santa_action_t SantaMessage::getAction() const {
|
||||
return action_;
|
||||
}
|
||||
|
||||
void SantaMessage::setAction(const santa_action_t action,
|
||||
const uint64_t microsecs) {
|
||||
void SantaMessage::setAction(
|
||||
const santa_action_t action, const uint64_t microsecs) {
|
||||
action_ = action;
|
||||
microsecs_ = microsecs;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -36,7 +36,7 @@ static NSMutableDictionary *registeredCommands;
|
||||
|
||||
int longestCommandName = 0;
|
||||
for (NSString *cmdName in registeredCommands) {
|
||||
if ([cmdName length] > longestCommandName) {
|
||||
if ((int)[cmdName length] > longestCommandName) {
|
||||
longestCommandName = (int)[cmdName length];
|
||||
}
|
||||
}
|
||||
@@ -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,88 +16,84 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTBinaryInfo.h"
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCodesignChecker.h"
|
||||
#import "SNTFileInfo.h"
|
||||
|
||||
@interface SNTCommandBinaryInfo : NSObject<SNTCommand>
|
||||
@end
|
||||
|
||||
@implementation SNTCommandBinaryInfo
|
||||
|
||||
REGISTER_COMMAND_NAME(@"binaryinfo");
|
||||
REGISTER_COMMAND_NAME(@"binaryinfo")
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
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 or empty file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
LOGI(@"Not a regular file");
|
||||
exit(1);
|
||||
}
|
||||
printf("%-19s: %s\n", "Path", [[fileInfo path] UTF8String]);
|
||||
printf("%-19s: %s\n", "SHA-256", [[fileInfo SHA256] UTF8String]);
|
||||
printf("%-19s: %s\n", "SHA-1", [[fileInfo SHA1] UTF8String]);
|
||||
printf("%-19s: %s\n", "Bundle Name", [[fileInfo bundleName] UTF8String]);
|
||||
printf("%-19s: %s\n", "Bundle Version", [[fileInfo bundleVersion] UTF8String]);
|
||||
printf("%-19s: %s\n", "Bundle Version Str", [[fileInfo bundleShortVersionString] UTF8String]);
|
||||
|
||||
// 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("%-19s: %s (%s)\n", "Type",
|
||||
[[fileInfo machoType] UTF8String],
|
||||
[[archs componentsJoinedByString:@", "] UTF8String]);
|
||||
} else {
|
||||
LOGI(@"%-20s: %@", "Type", [ftd machoType]);
|
||||
printf("%-19s: %s\n", "Type", [[fileInfo machoType] UTF8String]);
|
||||
}
|
||||
|
||||
SNTCodesignChecker *csc = [[SNTCodesignChecker alloc] initWithBinaryPath:filePath];
|
||||
|
||||
LOGI(@"%-20s: %s", "Code-signed", (csc) ? "Yes" : "No");
|
||||
printf("%-19s: %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.
|
||||
@@ -23,19 +23,23 @@
|
||||
|
||||
@implementation SNTCommandFlushCache
|
||||
|
||||
REGISTER_COMMAND_NAME(@"flushcache");
|
||||
REGISTER_COMMAND_NAME(@"flushcache")
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
164
Source/santactl/rule/SNTCommandRule.m
Normal file
164
Source/santactl/rule/SNTCommandRule.m
Normal file
@@ -0,0 +1,164 @@
|
||||
/// 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)printErrorUsageAndExit:(NSString *)error {
|
||||
printf("%s\n\n", [error UTF8String]);
|
||||
printf("%s\n", [[self longHelpText] UTF8String]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+ (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) {
|
||||
[self printErrorUsageAndExit:@"Missing action"];
|
||||
}
|
||||
|
||||
int state = RULESTATE_UNKNOWN;
|
||||
|
||||
if ([action compare:@"add" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
} else if ([action compare:@"remove" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
state = RULESTATE_REMOVE;
|
||||
} else {
|
||||
[self printErrorUsageAndExit:@"Unknown action"];
|
||||
}
|
||||
|
||||
NSString *customMsg = @"";
|
||||
NSString *SHA256 = nil;
|
||||
NSString *filePath = nil;
|
||||
|
||||
// parse arguments
|
||||
for (NSUInteger 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 - 1) {
|
||||
[self printErrorUsageAndExit:@"No message specified"];
|
||||
}
|
||||
|
||||
customMsg = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--path" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > arguments.count - 1) {
|
||||
[self printErrorUsageAndExit:@"No path specified"];
|
||||
}
|
||||
|
||||
filePath = [arguments objectAtIndex:i];
|
||||
} else if ([argument compare:@"--sha256" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
if (++i > arguments.count - 1) {
|
||||
[self printErrorUsageAndExit:@"No SHA-256 specified"];
|
||||
}
|
||||
|
||||
SHA256 = [arguments objectAtIndex:i];
|
||||
} else {
|
||||
[self printErrorUsageAndExit:[@"Unknown argument: %@" stringByAppendingString:argument]];
|
||||
}
|
||||
}
|
||||
|
||||
if (state == RULESTATE_UNKNOWN) {
|
||||
[self printErrorUsageAndExit:@"No state specified"];
|
||||
}
|
||||
|
||||
if (filePath) {
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:filePath];
|
||||
if (!fileInfo) {
|
||||
[self printErrorUsageAndExit:@"Provided path is not a regular file or executable bundle"];
|
||||
}
|
||||
|
||||
SHA256 = [fileInfo SHA256];
|
||||
} else if (SHA256) {
|
||||
} else {
|
||||
[self printErrorUsageAndExit:@"Either SHA-256 or path to file must be specified"];
|
||||
}
|
||||
|
||||
SNTRule *newRule = [[SNTRule alloc] init];
|
||||
newRule.shasum = SHA256;
|
||||
newRule.state = state;
|
||||
newRule.type = RULETYPE_BINARY;
|
||||
newRule.customMsg = customMsg;
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseRuleAddRule:newRule cleanSlate:NO reply:^{
|
||||
if (state == RULESTATE_REMOVE) {
|
||||
printf("Removed rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
|
||||
} else {
|
||||
printf("Added rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
|
||||
}
|
||||
exit(0);
|
||||
}];
|
||||
}
|
||||
|
||||
@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"
|
||||
|
||||
@@ -27,88 +22,67 @@
|
||||
|
||||
@implementation SNTCommandStatus
|
||||
|
||||
REGISTER_COMMAND_NAME(@"status");
|
||||
REGISTER_COMMAND_NAME(@"status")
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
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;
|
||||
[[daemonConn remoteObjectProxy] cacheCount:^(uint64_t count) {
|
||||
__block int64_t cacheCount = -1;
|
||||
[[daemonConn remoteObjectProxy] cacheCount:^(int64_t count) {
|
||||
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;
|
||||
[[daemonConn remoteObjectProxy] databaseRuleCounts:^(uint64_t binary, uint64_t certificate) {
|
||||
__block int64_t eventCount = -1, binaryRuleCount = -1, certRuleCount = -1;
|
||||
[[daemonConn remoteObjectProxy] databaseRuleCounts:^(int64_t binary, int64_t certificate) {
|
||||
binaryRuleCount = binary;
|
||||
certRuleCount = certificate;
|
||||
}];
|
||||
[[daemonConn remoteObjectProxy] databaseEventCount:^(uint64_t count) {
|
||||
[[daemonConn remoteObjectProxy] databaseEventCount:^(int64_t count) {
|
||||
eventCount = count;
|
||||
}];
|
||||
do { usleep(5000); } while (eventCount == -1 || binaryRuleCount == -1 || certRuleCount == -1);
|
||||
LOGI(@">>> Database Info");
|
||||
LOGI(@"%-30s | %d", "Binary Rules", binaryRuleCount);
|
||||
LOGI(@"%-30s | %d", "Certificate Rules", certRuleCount);
|
||||
LOGI(@"%-30s | %d", "Events Pending Upload", eventCount);
|
||||
LOGI(@"");
|
||||
|
||||
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"
|
||||
|
||||
#include <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;
|
||||
|
||||
NSUInteger 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,41 +12,71 @@
|
||||
/// 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.
|
||||
@property(nonatomic) NSString *userAgent;
|
||||
|
||||
/// 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.
|
||||
@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.
|
||||
@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.
|
||||
@property(nonatomic) NSString *clientCertIssuerCn;
|
||||
/// If set, this is the user-agent to send with requests, otherwise remains the default
|
||||
/// CFNetwork-based name.
|
||||
///
|
||||
@property(copy, nonatomic) NSString *userAgent;
|
||||
|
||||
///
|
||||
/// If set to YES, this session refuses redirect requests. Defaults to NO.
|
||||
///
|
||||
@property(nonatomic) BOOL refusesRedirects;
|
||||
|
||||
///
|
||||
/// If set, the server that we connect to _must_ match this string. Redirects to other
|
||||
/// hosts will not be allowed.
|
||||
///
|
||||
@property(copy, 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.
|
||||
///
|
||||
@property(copy, nonatomic) NSData *serverRootsPemData;
|
||||
|
||||
///
|
||||
/// If set and client certificate authentication is needed, the pkcs#12 file will be loaded
|
||||
///
|
||||
@property(copy, nonatomic) NSString *clientCertFile;
|
||||
|
||||
///
|
||||
/// If set and client certificate authentication is needed, the password being used for
|
||||
/// loading the clientCertFile
|
||||
///
|
||||
@property(copy, 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(copy, 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.
|
||||
///
|
||||
@property(copy, nonatomic) NSString *clientCertIssuerCn;
|
||||
|
||||
/// Designated initializer
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -32,7 +31,7 @@
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||
[config setTLSMinimumSupportedProtocol:kTLSProtocol12];
|
||||
[config setHTTPShouldUsePipelining:YES];
|
||||
return [self initWithSessionConfiguration:config];
|
||||
@@ -59,36 +58,37 @@
|
||||
NSURLProtectionSpace *protectionSpace = challenge.protectionSpace;
|
||||
|
||||
if (challenge.previousFailureCount > 0) {
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.serverHostname && ![self.serverHostname isEqual:protectionSpace.host]) {
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (![protectionSpace.protocol isEqual:NSURLProtectionSpaceHTTPS]) {
|
||||
LOGD(@"Protection Space: %@ is not a secure protocol", protectionSpace.protocol);
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
LOGE(@"%@ is not a secure protocol", protectionSpace.protocol);
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protectionSpace.receivesCredentialSecurely) {
|
||||
LOGD(@"Protection Space: secure authentication or protocol cannot be established");
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
LOGE(@"Secure authentication or protocol cannot be established.");
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, 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 {
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
LOGE(@"Server asked for client authentication but no usable client certificate found.");
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||
return;
|
||||
}
|
||||
} else if (authMethod == NSURLAuthenticationMethodServerTrust) {
|
||||
@@ -97,7 +97,8 @@
|
||||
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
|
||||
return;
|
||||
} else {
|
||||
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
|
||||
LOGE(@"Unable to verify server identity.");
|
||||
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -105,106 +106,165 @@
|
||||
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) {
|
||||
LOGD(@"Rejected redirection to: %@", request.URL);
|
||||
[task cancel]; // without this, the connection hangs until timeout!?!
|
||||
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 = NULL;
|
||||
|
||||
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) {
|
||||
LOGW(@"Unable to decode allowed distinguished name.");
|
||||
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 +288,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,12 +297,12 @@
|
||||
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;
|
||||
}
|
||||
|
||||
// Print details about the server's leaf certificate.
|
||||
SecCertificateRef firstCert = SecTrustGetCertificateAtIndex(protectionSpace.serverTrust, 0);
|
||||
SecCertificateRef firstCert = SecTrustGetCertificateAtIndex(serverTrust, 0);
|
||||
if (firstCert) {
|
||||
SNTCertificate *cert = [[SNTCertificate alloc] initWithSecCertificateRef:firstCert];
|
||||
LOGD(@"Server Trust: Server leaf cert: %@", cert);
|
||||
@@ -251,7 +311,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.
|
||||
@@ -20,34 +20,37 @@
|
||||
#import "SNTCommandSyncPostflight.h"
|
||||
#import "SNTCommandSyncPreflight.h"
|
||||
#import "SNTCommandSyncRuleDownload.h"
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@interface SNTCommandSync : NSObject<SNTCommand>
|
||||
@property NSURLSession *session;
|
||||
@property SNTXPCConnection *daemonConn;
|
||||
@property SNTCommandSyncStatus *progress;
|
||||
@property SNTCommandSyncState *syncState;
|
||||
@end
|
||||
|
||||
@implementation SNTCommandSync
|
||||
|
||||
REGISTER_COMMAND_NAME(@"sync");
|
||||
REGISTER_COMMAND_NAME(@"sync")
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Synchronizes Santa with the server";
|
||||
return @"Synchronizes Santa with a configured 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];
|
||||
@@ -94,24 +112,28 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
s.daemonConn = daemonConn;
|
||||
|
||||
// Gather some data needed during some sync stages
|
||||
s.progress = [[SNTCommandSyncStatus alloc] init];
|
||||
s.syncState = [[SNTCommandSyncState alloc] init];
|
||||
|
||||
s.progress.syncBaseURL = config.syncBaseURL;
|
||||
if (!s.progress.syncBaseURL) {
|
||||
s.syncState.syncBaseURL = config.syncBaseURL;
|
||||
if (!s.syncState.syncBaseURL) {
|
||||
LOGE(@"Missing SyncBaseURL. Can't sync without it.");
|
||||
exit(1);
|
||||
} else if (![s.syncState.syncBaseURL.scheme isEqual:@"https"]) {
|
||||
LOGW(@"SyncBaseURL is not over HTTPS!");
|
||||
}
|
||||
authURLSession.serverHostname = s.progress.syncBaseURL.host;
|
||||
authURLSession.serverHostname = s.syncState.syncBaseURL.host;
|
||||
|
||||
s.progress.machineID = config.machineIDOverride;
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
s.progress.machineID = [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
if (!s.progress.machineID || [s.progress.machineID isEqual:@""]) {
|
||||
s.syncState.machineID = config.machineID;
|
||||
if ([s.syncState.machineID length] == 0) {
|
||||
LOGE(@"Missing Machine ID. Can't sync without it.");
|
||||
exit(1);
|
||||
}
|
||||
s.progress.machineOwner = config.machineOwner;
|
||||
|
||||
s.syncState.machineOwner = config.machineOwner;
|
||||
if ([s.syncState.machineOwner length] == 0) {
|
||||
s.syncState.machineOwner = @"";
|
||||
LOGW(@"Missing Machine Owner.");
|
||||
}
|
||||
|
||||
if (arguments.count == 2 && [[arguments firstObject] isEqual:@"singleevent"]) {
|
||||
[s eventUploadSingleEvent:arguments[1]];
|
||||
@@ -122,98 +144,98 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
|
||||
- (void)preflight {
|
||||
[SNTCommandSyncPreflight performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Preflight complete");
|
||||
if (self.progress.uploadLogURL) {
|
||||
[self logUpload];
|
||||
} else {
|
||||
[self eventUpload];
|
||||
}
|
||||
} else {
|
||||
LOGE(@"Preflight failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
if (success) {
|
||||
LOGI(@"Preflight complete");
|
||||
if (self.syncState.uploadLogURL) {
|
||||
[self logUpload];
|
||||
} else {
|
||||
[self eventUpload];
|
||||
}
|
||||
} else {
|
||||
LOGE(@"Preflight failed, aborting run");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)logUpload {
|
||||
[SNTCommandSyncLogUpload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
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");
|
||||
} else {
|
||||
LOGE(@"Log upload failed, continuing anyway");
|
||||
}
|
||||
[self eventUpload];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)eventUpload {
|
||||
[SNTCommandSyncEventUpload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
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
|
||||
syncState:self.syncState
|
||||
daemonConn:self.daemonConn
|
||||
completionHandler:^(BOOL success) {
|
||||
if (success) {
|
||||
LOGI(@"Event upload complete");
|
||||
exit(0);
|
||||
} else {
|
||||
LOGW(@"Event upload failed");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)ruleDownload {
|
||||
[SNTCommandSyncRuleDownload performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
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 {
|
||||
[SNTCommandSyncPostflight performSyncInSession:self.session
|
||||
progress:self.progress
|
||||
syncState:self.syncState
|
||||
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
|
||||
|
||||
83
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
83
Source/santactl/sync/SNTCommandSyncConstants.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
extern NSString * const kURLPreflight;
|
||||
extern NSString * const kURLEventUpload;
|
||||
extern NSString * const kURLRuleDownload;
|
||||
extern NSString * const kURLPostflight;
|
||||
|
||||
extern NSString * const kSerialNumber;
|
||||
extern NSString * const kHostname;
|
||||
extern NSString * const kSantaVer;
|
||||
extern NSString * const kOSVer;
|
||||
extern NSString * const kOSBuild;
|
||||
extern NSString * const kPrimaryUser;
|
||||
extern NSString * const kRequestCleanSync;
|
||||
extern NSString * const kBatchSize;
|
||||
extern NSString * const kUploadLogsURL;
|
||||
extern NSString * const kClientMode;
|
||||
extern NSString * const kClientModeMonitor;
|
||||
extern NSString * const kClientModeLockdown;
|
||||
extern NSString * const kCleanSync;
|
||||
extern NSString * const kWhitelistRegex;
|
||||
|
||||
extern NSString * const kEvents;
|
||||
extern NSString * const kFileSHA256;
|
||||
extern NSString * const kFilePath;
|
||||
extern NSString * const kFileName;
|
||||
extern NSString * const kExecutingUser;
|
||||
extern NSString * const kExecutionTime;
|
||||
extern NSString * const kDecision;
|
||||
extern NSString * const kDecisionAllowUnknown;
|
||||
extern NSString * const kDecisionAllowBinary;
|
||||
extern NSString * const kDecisionAllowCertificate;
|
||||
extern NSString * const kDecisionAllowScope;
|
||||
extern NSString * const kDecisionBlockUnknown;
|
||||
extern NSString * const kDecisionBlockBinary;
|
||||
extern NSString * const kDecisionBlockCertificate;
|
||||
extern NSString * const kDecisionBlockScope;
|
||||
extern NSString * const kDecisionUnknown;
|
||||
extern NSString * const kLoggedInUsers;
|
||||
extern NSString * const kCurrentSessions;
|
||||
extern NSString * const kFileBundleID;
|
||||
extern NSString * const kFileBundleName;
|
||||
extern NSString * const kFileBundleVersion;
|
||||
extern NSString * const kFileBundleShortVersionString;
|
||||
extern NSString * const kPID;
|
||||
extern NSString * const kPPID;
|
||||
extern NSString * const kParentName;
|
||||
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;
|
||||
|
||||
extern NSString * const kBackoffInterval;
|
||||
85
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
85
Source/santactl/sync/SNTCommandSyncConstants.m
Normal file
@@ -0,0 +1,85 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
|
||||
NSString * const kURLPreflight = @"preflight/";
|
||||
NSString * const kURLEventUpload = @"eventupload/";
|
||||
NSString * const kURLRuleDownload = @"ruledownload/";
|
||||
NSString * const kURLPostflight = @"postflight/";
|
||||
|
||||
NSString * const kSerialNumber = @"serial_num";
|
||||
NSString * const kHostname = @"hostname";
|
||||
NSString * const kSantaVer = @"santa_version";
|
||||
NSString * const kOSVer = @"os_version";
|
||||
NSString * const kOSBuild = @"os_build";
|
||||
NSString * const kPrimaryUser = @"primary_user";
|
||||
NSString * const kRequestCleanSync = @"request_clean_sync";
|
||||
NSString * const kBatchSize = @"batch_size";
|
||||
NSString * const kUploadLogsURL = @"upload_logs_url";
|
||||
NSString * const kClientMode = @"client_mode";
|
||||
NSString * const kClientModeMonitor = @"MONITOR";
|
||||
NSString * const kClientModeLockdown = @"LOCKDOWN";
|
||||
NSString * const kCleanSync = @"clean_sync";
|
||||
NSString * const kWhitelistRegex = @"whitelist_regex";
|
||||
|
||||
NSString * const kEvents = @"events";
|
||||
NSString * const kFileSHA256 = @"file_sha256";
|
||||
NSString * const kFilePath = @"file_path";
|
||||
NSString * const kFileName = @"file_name";
|
||||
NSString * const kExecutingUser = @"executing_user";
|
||||
NSString * const kExecutionTime = @"execution_time";
|
||||
NSString * const kDecision = @"decision";
|
||||
NSString * const kDecisionAllowUnknown = @"ALLOW_UNKNOWN";
|
||||
NSString * const kDecisionAllowBinary = @"ALLOW_BINARY";
|
||||
NSString * const kDecisionAllowCertificate = @"ALLOW_CERTIFICATE";
|
||||
NSString * const kDecisionAllowScope = @"ALLOW_SCOPE";
|
||||
NSString * const kDecisionBlockUnknown = @"BLOCK_UNKNOWN";
|
||||
NSString * const kDecisionBlockBinary = @"BLOCK_BINARY";
|
||||
NSString * const kDecisionBlockCertificate = @"BLOCK_CERTIFICATE";
|
||||
NSString * const kDecisionBlockScope = @"BLOCK_SCOPE";
|
||||
NSString * const kDecisionUnknown = @"UNKNOWN";
|
||||
NSString * const kLoggedInUsers = @"logged_in_users";
|
||||
NSString * const kCurrentSessions = @"current_sessions";
|
||||
NSString * const kFileBundleID = @"file_bundle_id";
|
||||
NSString * const kFileBundleName = @"file_bundle_name";
|
||||
NSString * const kFileBundleVersion = @"file_bundle_version";
|
||||
NSString * const kFileBundleShortVersionString = @"file_bundle_version_string";
|
||||
NSString * const kPID = @"pid";
|
||||
NSString * const kPPID = @"ppid";
|
||||
NSString * const kParentName = @"parent_name";
|
||||
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";
|
||||
|
||||
NSString * const kBackoffInterval = @"backoff";
|
||||
@@ -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,20 +12,20 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncEventUpload : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
+ (void)uploadSingleEventWithSHA1:(NSString *)SHA1
|
||||
session:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
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,7 +16,9 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCertificate.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
@@ -24,11 +26,11 @@
|
||||
@implementation SNTCommandSyncEventUpload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"eventupload/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseEventsPending:^(NSArray *events) {
|
||||
if ([events count] == 0) {
|
||||
@@ -37,21 +39,21 @@
|
||||
[self uploadEventsFromArray:events
|
||||
toURL:url
|
||||
inSession:session
|
||||
batchSize:progress.eventBatchSize
|
||||
batchSize:syncState.eventBatchSize
|
||||
daemonConn:daemonConn
|
||||
completionHandler:handler];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (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]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA1:SHA1 withReply:^(SNTStoredEvent *event) {
|
||||
+ (void)uploadSingleEventWithSHA256:(NSString *)SHA256
|
||||
session:(NSURLSession *)session
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[kURLEventUpload stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
[[daemonConn remoteObjectProxy] databaseEventForSHA256:SHA256 reply:^(SNTStoredEvent *event) {
|
||||
if (!event) {
|
||||
handler(YES);
|
||||
return;
|
||||
@@ -69,76 +71,50 @@
|
||||
+ (void)uploadEventsFromArray:(NSArray *)events
|
||||
toURL:(NSURL *)url
|
||||
inSession:(NSURLSession *)session
|
||||
batchSize:(int32_t)batchSize
|
||||
batchSize:(NSUInteger)batchSize
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSMutableArray *uploadEvents = [[NSMutableArray alloc] init];
|
||||
|
||||
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: %ld %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
LOGI(@"Uploaded %d events", eventIds.count);
|
||||
LOGI(@"Uploaded %lu events", eventIds.count);
|
||||
|
||||
[[daemonConn remoteObjectProxy] databaseRemoveEventsWithIDs:eventIds];
|
||||
|
||||
NSArray *nextEvents = [events subarrayWithRange:NSMakeRange(eventIds.count,
|
||||
events.count - eventIds.count)];
|
||||
|
||||
if (nextEvents.count == 0) {
|
||||
handler(YES);
|
||||
} else {
|
||||
@@ -153,4 +129,61 @@
|
||||
}] 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, kLoggedInUsers, event.loggedInUsers);
|
||||
ADDKEY(newEvent, kCurrentSessions, event.currentSessions);
|
||||
|
||||
switch (event.decision) {
|
||||
case EVENTSTATE_ALLOW_UNKNOWN: ADDKEY(newEvent, kDecision, kDecisionAllowUnknown); break;
|
||||
case EVENTSTATE_ALLOW_BINARY: ADDKEY(newEvent, kDecision, kDecisionAllowBinary); break;
|
||||
case EVENTSTATE_ALLOW_CERTIFICATE:
|
||||
ADDKEY(newEvent, kDecision, kDecisionAllowCertificate);
|
||||
break;
|
||||
case EVENTSTATE_ALLOW_SCOPE: ADDKEY(newEvent, kDecision, kDecisionAllowScope); break;
|
||||
case EVENTSTATE_BLOCK_UNKNOWN: ADDKEY(newEvent, kDecision, kDecisionBlockUnknown); break;
|
||||
case EVENTSTATE_BLOCK_BINARY: ADDKEY(newEvent, kDecision, kDecisionBlockBinary); break;
|
||||
case EVENTSTATE_BLOCK_CERTIFICATE:
|
||||
ADDKEY(newEvent, kDecision, kDecisionBlockCertificate);
|
||||
break;
|
||||
case EVENTSTATE_BLOCK_SCOPE: ADDKEY(newEvent, kDecision, kDecisionBlockScope); break;
|
||||
default: ADDKEY(newEvent, kDecision, kDecisionUnknown);
|
||||
}
|
||||
|
||||
ADDKEY(newEvent, kFileBundleID, event.fileBundleID);
|
||||
ADDKEY(newEvent, kFileBundleName, event.fileBundleName);
|
||||
ADDKEY(newEvent, kFileBundleVersion, event.fileBundleVersion);
|
||||
ADDKEY(newEvent, kFileBundleShortVersionString, event.fileBundleVersionString);
|
||||
|
||||
ADDKEY(newEvent, kPID, event.pid);
|
||||
ADDKEY(newEvent, kPPID, event.ppid);
|
||||
ADDKEY(newEvent, kParentName, event.parentName);
|
||||
|
||||
NSMutableArray *signingChain = [NSMutableArray arrayWithCapacity:event.signingChain.count];
|
||||
for (NSUInteger 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.
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncLogUpload : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -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,72 @@
|
||||
|
||||
#import "SNTCommandSyncLogUpload.h"
|
||||
|
||||
#import "NSData+Zlib.h"
|
||||
|
||||
#include "SNTCommonEnums.h"
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
|
||||
@implementation SNTCommandSyncLogUpload
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = progress.uploadLogURL;
|
||||
NSURL *url = syncState.uploadLogURL;
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
NSString *boundary = @"santa-sync-upload-boundary";
|
||||
NSString *boundary = @"----santa-sync-upload-boundary";
|
||||
|
||||
NSString *contentType =
|
||||
[NSString stringWithFormat:@"multipart/form-data; charset=UTF-8; boundary=%@", boundary];
|
||||
[req setValue:contentType forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSArray *logsToUpload = [self logsToUpload];
|
||||
|
||||
// Upload the logs
|
||||
[[session uploadTaskWithRequest:req
|
||||
fromData:[self requestBodyWithLogs:logsToUpload andBoundary:boundary]
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGE(@"HTTP Response: %ld %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
LOGI(@"Uploaded %lu logs", [logsToUpload count]);
|
||||
handler(YES);
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
+ (NSData *)requestBodyWithLogs:(NSArray *)logsToUpload andBoundary:(NSString *)boundary {
|
||||
// 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];
|
||||
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]];
|
||||
|
||||
return reqBody;
|
||||
}
|
||||
|
||||
+ (NSArray *)logsToUpload {
|
||||
// General logs
|
||||
NSMutableArray *logsToUpload = [@[ @"/var/log/santa.log",
|
||||
@"/var/log/system.log" ] mutableCopy];
|
||||
@@ -51,38 +96,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.
|
||||
@@ -12,13 +12,13 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
@class SNTCommandSyncStatus;
|
||||
@class SNTCommandSyncState;
|
||||
@class SNTXPCConnection;
|
||||
|
||||
@interface SNTCommandSyncPostflight : NSObject
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler;
|
||||
|
||||
|
||||
@@ -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,26 +16,39 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "SNTCommandSyncStatus.h"
|
||||
#import "SNTCommandSyncConstants.h"
|
||||
#import "SNTCommandSyncState.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
@implementation SNTCommandSyncPostflight
|
||||
|
||||
+ (void)performSyncInSession:(NSURLSession *)session
|
||||
progress:(SNTCommandSyncStatus *)progress
|
||||
syncState:(SNTCommandSyncState *)syncState
|
||||
daemonConn:(SNTXPCConnection *)daemonConn
|
||||
completionHandler:(void (^)(BOOL success))handler {
|
||||
NSURL *url = [NSURL URLWithString:[@"postflight/" stringByAppendingString:progress.machineID]
|
||||
relativeToURL:progress.syncBaseURL];
|
||||
NSURL *url = [NSURL URLWithString:[kURLPostflight stringByAppendingString:syncState.machineID]
|
||||
relativeToURL:syncState.syncBaseURL];
|
||||
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
|
||||
[[session dataTaskWithRequest:req completionHandler:^(NSData *data,
|
||||
NSURLResponse *response,
|
||||
NSError *error) {
|
||||
if ([(NSHTTPURLResponse *)response statusCode] != 200) {
|
||||
LOGD(@"HTTP Response Code: %d", [(NSHTTPURLResponse *)response statusCode]);
|
||||
long statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode != 200) {
|
||||
LOGE(@"HTTP Response: %ld %@",
|
||||
statusCode,
|
||||
[[NSHTTPURLResponse localizedStringForStatusCode:statusCode] capitalizedString]);
|
||||
handler(NO);
|
||||
} else {
|
||||
NSDictionary *r = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
|
||||
NSString *backoffInterval = r[kBackoffInterval];
|
||||
if (backoffInterval) {
|
||||
[[daemonConn remoteObjectProxy] setNextSyncInterval:[backoffInterval intValue] reply:^{}];
|
||||
}
|
||||
|
||||
handler(YES);
|
||||
}
|
||||
}] resume];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user