Compare commits

...

44 Commits

Author SHA1 Message Date
Russell Hancox
3c2a88144c santad: Wait for driver appearance using IOKit notifications. (#278)
Continue loading without driver, report status in santactl.
2018-06-12 16:15:41 -04:00
dgw
3651f18566 readme: s/precendence/precedence/ (#283) 2018-06-12 15:01:42 -04:00
Russell Hancox
472fea75b1 KernelTests: Simplify kernel tests (#282)
This change does 2 major things:

1) Makes the test runnable from within Xcode, unloading any running
santad and santa-driver, loading the just-built driver from the same folder and
then running each test.

2) Makes each test responsible for declaring what should happen to
incoming requests from the driver, instead of keeping all of that
code near the top of the file. This makes each test much clearer in what
should be happening.
2018-06-12 09:53:20 -04:00
Russell Hancox
e1b5438865 santa-driver: Re-factor some destruction methods (#281) 2018-06-11 12:54:29 -04:00
Russell Hancox
fbbf523333 santa-driver: Stop catching hasdirtyblks, the loader handles this (#280) 2018-06-06 18:56:00 -04:00
Russell Hancox
15fa53d744 santa-driver: Switch to a struct for vnode IDs, holding both the file… (#276)
santa-driver: Switch to a struct for vnode IDs, holding both the filesystem ID and vnode ID.

Also drop the separate caches for root/non-root as this doesn't offer any benefit anymore.
2018-06-05 06:43:49 -04:00
Russell Hancox
9595f80fde santad: Don't get code signature info for non Mach-O's. (#277) 2018-06-05 06:43:11 -04:00
Russell Hancox
61a67e45c1 SantaCache: Add command to print histogram of bucket distribution (#275)
* SantaCache: Add santactl command to print histogram of bucket distribution.

This currently only prints the distribution of the non-root cache. In the near future I'll unify the caches again which stops this being a problem.
2018-06-01 17:02:39 -04:00
Russell Hancox
143e690dab SantaCache: Add very basic distribution test (#273)
* SantaCache: Add very basic distribution test
2018-06-01 13:11:24 -04:00
Russell Hancox
ebd507f143 Project: Update cocoapods, again (#274) 2018-06-01 12:01:21 -04:00
Russell Hancox
f71bc0a8f7 santa-driver: Fix cache CAS operations, which haven't been working (#272)
* santa-driver: Fix cache CAS operations, which haven't really been working.
2018-06-01 11:38:25 -04:00
Russell Hancox
edc0c72464 SantaCache: Templatize key types (#271) 2018-05-30 15:50:23 -04:00
Tom Burgin
c3ce4f718b Update configuration.md (#270) 2018-05-30 11:06:45 -04:00
Tom Burgin
40ee482973 Update SNTSyslogEventLog.m (#269)
remove extra space
2018-05-29 16:39:18 -04:00
Mitchell Grenier
a5d2e6fdd2 Optional MachineID for Logs (#256)
* First draft, no UUID caching

* Cache UUID in SNTEventLog super class

* Add a configuration flag for UUID decoration

* Port from UUID to MachineID

* KVO complicance

* Remove extra newline I accidentally introduced
2018-05-29 16:16:21 -04:00
Tom Burgin
e9a835a642 log deny because of dirty vnode (#267)
* log dirty vnode blocks

* review update
2018-05-25 14:16:16 -04:00
Tom Burgin
ac7b95ceb6 santa-driver: do not invalidate cached decisions on KAUTH_VNODE_ACCESS (#266)
* santa-driver: do not invalidate cached decisions on KAUTH_VNODE_ACCESS

* downtown
2018-05-25 10:47:48 -04:00
Russell Hancox
055b2d8ede Update project for Xcode 9.1, add codesigning flags (#264)
* Project: Update project to Xcode 9.1 and handle all the new warnings that entails.

* Project: Add library-validation and kill flags to codesigning options
2018-05-22 10:13:59 -04:00
Russell Hancox
a75cd0a0f5 Update README.md (#263)
Update the sync client section to point at known open-source solutions, remove the Xcode 7.3.1 build requirement
2018-05-18 12:26:37 -04:00
Matthew Suozzo
2b1ddf9a4e Fix typo in sync help text (#259) 2018-05-09 21:53:51 -04:00
Tom Burgin
b70442e483 Project: Use MOLXPCConnection (#258)
* Project: Use MOLXPCConnection

* review fixes
2018-05-09 11:40:35 -04:00
Tom Burgin
798b0fab15 fileinfo: whitelist bundle extensions when performing an ancestor search (#257)
* fileinfo: whitelist bundle extensions when performing an ancestor search

* fix tests

* conform to russell's every whim
2018-05-07 13:57:58 -04:00
Russell Hancox
e8630132d7 Project: make building on case-sensitive volumes work (#255) 2018-04-27 12:58:54 -04:00
Russell Hancox
273ae5f21a santad: Missed an import (#254) 2018-04-27 10:51:53 -04:00
Tom Burgin
06b688fef4 Update .travis.yml (#253) 2018-04-26 17:23:32 -04:00
Russell Hancox
59cc038ab2 All: stop using @import for reasons. (#252) 2018-04-26 17:19:19 -04:00
Tom Burgin
ea5a6c3438 downstream --> upstream changes (#251) 2018-04-25 16:16:56 -04:00
Tom Burgin
e2adfdf3cf Add EventLog Docs (#250) 2018-04-24 16:33:53 -04:00
Tom Burgin
5ee6531627 santad / santactl: validate all architectures within universal binaries (#249) 2018-04-24 16:11:49 -04:00
Tom Burgin
1cf8ee09e1 sync-state: Mitigate com.apple.ManagedClient flapping (#248)
* sync-state: Mitigate com.apple.ManagedClient flapping

* 10 min
2018-04-09 13:34:33 -04:00
Tom Burgin
4a2cf9d722 santad: event logger (#246)
* kext symbols

* santad: Create FileLog and Syslog options

* review updates

* review updates

* be a good citizen and let go of things you do not need
2018-04-03 13:15:12 -04:00
Tom Burgin
6a6a32c1cf santactl: Update to MOLFCMClient v1.7 (#245) 2018-03-13 13:07:44 -04:00
Tom Burgin
ce03611b52 santabs: Serialize calls to -[SNTBundleService createConnection] (#244) 2018-03-12 17:04:53 -04:00
Tom Burgin
bbe9f83878 Import fixes (#243)
* All: use common import style for cocoapods <PodName/PodName.h>

* All: Update Pods
2018-03-12 16:02:55 -04:00
Tom Burgin
40e6c6aa92 sync-state: perform sync-state operations on a serial q (#242)
* sync-state serial

* delete it
2018-03-07 17:35:02 -05:00
Tom Burgin
9f6ccf092a code cleanup (#241) 2018-02-26 10:51:44 -05:00
Tom Burgin
d4ba4b082f codesign check: verify all architectures (#239)
* fileinfo rule: don't use certs that have codesigning errors

* pods: MOLCodesignChecker --> 1.8
2018-02-22 14:41:47 -05:00
Tom Burgin
cce43829eb use MOLFCMClient v1.5 (#238) 2018-02-16 14:35:52 -05:00
johnl
c1bfbac2fe Various small fixes to README.md (#237)
* Various small fixes to README.md

* Apply changes
2018-02-13 11:06:28 -05:00
Tom Burgin
fc87cde668 config: use KVO (#234)
* config: atomically update config

* config: add an explanation for sleep usage

* config: use mobileconfig in the getters

* config: cleanup file watcher

* config: spell

* config: clear or reload sync state on sync base url change

* config: Use KVO and Dependent Keys

* config: remove debug log

* config: review updates

* config: update rule sync getter and setter names

* config: get logical
2018-02-07 13:59:00 -05:00
Tom Burgin
400c413029 config: add option to disable mode change notifications (#235)
* config: add option to disable mode change notifications

* config: don't do extra work

* config: handle none, default and custom

* config: cleaner
2018-02-02 12:01:51 -05:00
Tom Burgin
0e6eb45732 santa-driver: add an acknowledge feature to allow timeouts (#220)
* santa-driver: Add an acknowledge feature to allow timeouts for lost requests

* project: cocoapods 1.3.1 update

* review updates
2018-01-26 11:33:54 -05:00
Tom Burgin
7ca2028c19 santabs: don't try to lookup nil bundle paths (#233) 2018-01-26 11:33:04 -05:00
Tom Burgin
08144b54a7 docs: updated configuration details (#232)
* docs: updated configuration details

* config: add example mobileconfig
2018-01-24 21:07:48 -05:00
140 changed files with 3066 additions and 2496 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ Santa.xcodeproj/project.xcworkspace
Santa.xcworkspace/xcuserdata
Santa.xcworkspace/xcshareddata
Source/DevelopmentTeam.xcconfig
default.profraw

View File

@@ -4,7 +4,7 @@ cache:
- bundler
- cocoapods
sudo: false
osx_image: xcode7
osx_image: xcode9.3
before_install:
- gem install cocoapods xcpretty

View File

@@ -32,6 +32,7 @@ PACKAGE_VERSION:=$(shell curl -fs https://api.github.com/repos/google/santa/rele
# | |-- com.google.santad.plist
# | |-- com.google.santagui.plist
# | +-- com.google.santa.asl.conf
# | +-- com.google.santa.newsyslog.conf
# +--dsym
# |-- santa-driver.kext.dSYM
# |-- Santa.app.dSYM
@@ -44,6 +45,7 @@ PAYLOAD:=pack-Library-Extensions-santa-driver.kext \
pack-Library-LaunchDaemons-com.google.santad.plist \
pack-Library-LaunchAgents-com.google.santagui.plist \
pack-etc-asl-com.google.santa.asl.conf \
pack-etc-newsyslog.d-com.google.santa.newsyslog.conf \
pack-script-preinstall \
pack-script-postinstall
@@ -52,6 +54,7 @@ Santa.app: download
com.google.santad.plist: download
com.google.santagui.plist: download
com.google.santa.asl.conf: download
com.google.santa.newsyslog.conf: download
download:
$(if $(PACKAGE_VERSION),, $(error GitHub API returned unexpected result. Wait a while and try again))
@@ -65,6 +68,12 @@ pack-etc-asl-com.google.santa.asl.conf: com.google.santa.asl.conf l_private_etc
@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-etc-newsyslog.d-com.google.santa.newsyslog.conf: com.google.santa.newsyslog.conf l_private_etc
@sudo mkdir -p ${WORK_D}/private/etc/newsyslog.d
@sudo chown root:wheel ${WORK_D}/private/etc/newsyslog.d
@sudo chmod 755 ${WORK_D}/private/etc/newsyslog.d
@sudo install -m 644 -o root -g wheel com.google.santa.newsyslog.conf ${WORK_D}/private/etc/newsyslog.d
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
@@ -79,6 +88,7 @@ myclean:
@rm -rf santa-driver.kext
@rm -f config.plist
@rm -f com.google.santa.asl.conf
@rm -f com.google.santa.newsyslog.conf
@rm -f com.google.santad.plist
@rm -f com.google.santagui.plist
@rm -f install.sh

View File

@@ -0,0 +1,2 @@
# logfilename [owner:group] mode count size(KiB) when flags [/pid_file] # [sig_num]
/var/db/santa/santa.log root:wheel 644 10 25000 * NZ

View File

@@ -20,7 +20,5 @@
<true />
<key>ProcessType</key>
<string>Interactive</string>
<key>ThrottleInterval</key>
<integer>1</integer>
</dict>
</plist>

View File

@@ -42,6 +42,7 @@ mkdir -p /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/
/bin/cp ${SOURCE}/conf/com.google.santa.newsyslog.conf /etc/newsyslog.d/
# Reload syslogd to pick up ASL configuration change.
/usr/bin/killall -HUP syslogd

View File

@@ -19,6 +19,7 @@ user=$(/usr/bin/stat -f '%u' /dev/console)
/bin/rm -f /Library/LaunchAgents/com.google.santagui.plist
/bin/rm -f /Library/LaunchDaemons/com.google.santad.plist
/bin/rm -f /private/etc/asl/com.google.santa.asl.conf
/bin/rm -f /private/etc/newsyslog.d/com.google.santa.newsyslog.conf
/bin/rm -f /usr/local/bin/santactl # just a symlink
#uncomment to remove the config file and all databases, log files
#/bin/rm -rf /var/db/santa

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadContent</key>
<dict>
<key>com.google.santa</key>
<dict>
<key>Forced</key>
<array>
<dict>
<key>mcx_preference_settings</key>
<dict>
<key>BannedBlockMessage</key>
<string>This application has been banned</string>
<key>ClientMode</key>
<integer>1</integer>
<key>EnablePageZeroProtection</key>
<false/>
<key>EventDetailText</key>
<string>Open sync server</string>
<key>EventDetailURL</key>
<string>https://sync-server-hostname/blockables/%file_sha%</string>
<key>FileChangesRegex</key>
<string>^/(?!(?:private/tmp|Library/(?:Caches|Managed Installs/Logs|(?:Managed )?Preferences))/)</string>
<key>MachineIDKey</key>
<string>MachineUUID</string>
<key>MachineIDPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>MachineOwnerKey</key>
<string>Owner</string>
<key>MachineOwnerPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>ModeNotificationLockdown</key>
<string>Entering Lockdown mode</string>
<key>ModeNotificationMonitor</key>
<string>Entering Monitor mode&lt;br/&gt;Please be careful!</string>
<key>MoreInfoURL</key>
<string>https://sync-server-hostname/moreinfo</string>
<key>SyncBaseURL</key>
<string>https://sync-server-hostname/api/santa/</string>
<key>UnknownBlockMessage</key>
<string>This application has been blocked from executing.</string>
</dict>
</dict>
</array>
</dict>
</dict>
<key>PayloadEnabled</key>
<true/>
<key>PayloadIdentifier</key>
<string>0342c558-a101-4a08-a0b9-40cc00039ea5</string>
<key>PayloadType</key>
<string>com.apple.ManagedClient.preferences</string>
<key>PayloadUUID</key>
<string>0342c558-a101-4a08-a0b9-40cc00039ea5</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string>com.google.santa</string>
<key>PayloadDisplayName</key>
<string>com.google.santa</string>
<key>PayloadIdentifier</key>
<string>com.google.santa</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadRemovalDisallowed</key>
<true/>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>9020fb2d-cab3-420f-9268-acca4868bdd0</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>

View File

@@ -1,8 +1,12 @@
# Important
Santa v0.9.21 has moved to using an Apple [Configuration Profile](https://developer.apple.com/library/content/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html) to manage the local configuration. The old config file (`/var/db/santa/config.plist`) is no longer used.
# Configuration
Two configuration methods can be used to control Santa: local configuration and a sync server controlled configuration. There are certain options that can only be controlled with a local configuration and others that can only be controlled with a sync server controlled configuration. Additionally, there are options that can be controlled by both.
Two configuration methods can be used to control Santa: a local configuration profile and a sync server controlled configuration. There are certain options that can only be controlled with a local configuration profile and others that can only be controlled with a sync server controlled configuration. Additionally, there are options that can be controlled by both.
## Local Configuration
## Local Configuration Profile
| Key | Value Type | Description |
| ----------------------------- | ---------- | ---------------------------------------- |
@@ -31,8 +35,11 @@ Two configuration methods can be used to control Santa: local configuration and
| MachineOwnerKey | String | The key to use on MachineOwnerPlist. |
| MachineIDPlist | String | The path to a plist that contains the MachineOwnerKey / value pair. |
| MachineIDKey | String | The key to use on MachineIDPlist. |
| EventLogType | String | Defines how event logs are stored. Options are 1) syslog: Sent to ASL or ULS (if built with the 10.12 SDK or later). 2) filelog: Sent to a file on disk. Use EventLogPath to specify a path. Defaults to filelog |
| EventLogPath | String | If EventLogType is set to filelog, EventLogPath will provide the path to save logs. Defaults to /var/db/santa/santa.log. If you change this value ensure you also update com.google.santa.newsyslog.conf with the new path. |
| EnableMachineIDDecoration | Bool | If YES, this appends the MachineID to the end of each log line. Defaults to NO. |
*protected keys: If a sync server is configured, this setting cannot be changed while santad is running as it is assumed the setting will be provided by the sync server.
*overridable by the sync server: run `santactl status` to check the current running config
##### EventDetailURL
@@ -50,49 +57,108 @@ This property contains a kind of format string to be turned into the URL to send
For example: `https://sync-server-hostname/%machine_id%/%file_sha%`
##### Example Config
##### Example Configuration Profile
Here is an example of a configuration that could be set.
Here is an example of a configuration profile that could be set. It was generated with Tim Sutton's great [mcxToProfile](https://github.com/timsutton/mcxToProfile) tool. A copy is also available [here](com.google.santa.example.mobileconfig).
A few key points to when creating your configuration profile:
* `com.google.santa` needs to be the key inside `PayloadContent`
* The `PayloadScope` needs to be `System`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BannedBlockMessage</key>
<string>This application has been banned</string>
<key>ClientMode</key>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadContent</key>
<dict>
<key>com.google.santa</key>
<dict>
<key>Forced</key>
<array>
<dict>
<key>mcx_preference_settings</key>
<dict>
<key>BannedBlockMessage</key>
<string>This application has been banned</string>
<key>ClientMode</key>
<integer>1</integer>
<key>EnablePageZeroProtection</key>
<false/>
<key>EventDetailText</key>
<string>Open sync server</string>
<key>EventDetailURL</key>
<string>https://sync-server-hostname/blockables/%file_sha%</string>
<key>FileChangesRegex</key>
<string>^/(?!(?:private/tmp|Library/(?:Caches|Managed Installs/Logs|(?:Managed )?Preferences))/)</string>
<key>MachineIDKey</key>
<string>MachineUUID</string>
<key>MachineIDPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>MachineOwnerKey</key>
<string>Owner</string>
<key>MachineOwnerPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>ModeNotificationLockdown</key>
<string>Entering Lockdown mode</string>
<key>ModeNotificationMonitor</key>
<string>Entering Monitor mode&lt;br/&gt;Please be careful!</string>
<key>MoreInfoURL</key>
<string>https://sync-server-hostname/moreinfo</string>
<key>SyncBaseURL</key>
<string>https://sync-server-hostname/api/santa/</string>
<key>UnknownBlockMessage</key>
<string>This application has been blocked from executing.</string>
</dict>
</dict>
</array>
</dict>
</dict>
<key>PayloadEnabled</key>
<true/>
<key>PayloadIdentifier</key>
<string>0342c558-a101-4a08-a0b9-40cc00039ea5</string>
<key>PayloadType</key>
<string>com.apple.ManagedClient.preferences</string>
<key>PayloadUUID</key>
<string>0342c558-a101-4a08-a0b9-40cc00039ea5</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string>com.google.santa</string>
<key>PayloadDisplayName</key>
<string>com.google.santa</string>
<key>PayloadIdentifier</key>
<string>com.google.santa</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadRemovalDisallowed</key>
<true/>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>9020fb2d-cab3-420f-9268-acca4868bdd0</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>EnablePageZeroProtection</key>
<false/>
<key>EventDetailText</key>
<string>Open sync server</string>
<key>EventDetailURL</key>
<string>https://sync-server-hostname/blockables/%file_sha%</string>
<key>FileChangesRegex</key>
<string>^/(?!(?:private/tmp|Library/(?:Caches|Managed Installs/Logs|(?:Managed )?Preferences))/)</string>
<key>MachineIDKey</key>
<string>MachineUUID</string>
<key>MachineIDPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>MachineOwnerKey</key>
<string>Owner</string>
<key>MachineOwnerPlist</key>
<string>/Library/Preferences/com.company.machine-mapping.plist</string>
<key>ModeNotificationLockdown</key>
<string>Entering Lockdown mode</string>
<key>ModeNotificationMonitor</key>
<string>Entering Monitor mode&lt;br/&gt;Please be careful!</string>
<key>MoreInfoURL</key>
<string>https://sync-server-hostname/moreinfo</string>
<key>SyncBaseURL</key>
<string>https://sync-server-hostname/api/santa/</string>
<key>UnknownBlockMessage</key>
<string>This application has been blocked from executing.</string>
</dict>
</plist>
```
Configuration profiles have a `.mobileconfig` file extension. There are many ways to install configuration profiles:
* Double click them in Finder
* Use the `/usr/bin/profiles` tool
* Use an MDM
## Sync server Provided Configuration
| Key | Value Type | Description |

View File

@@ -35,28 +35,19 @@ Running Santa in Lockdown Mode will stop all blacklisted binaries and additional
##### Changing Modes
There are two ways to change the running mode: changing the config.plist and with a sync server configuration.
There are two ways to change the running mode: changing the configuration profile and with a sync server configuration.
###### Change modes with the config.plist
###### Change modes with the configuration profile
The `ClientMode` config key is protected while santad is running and will revert any attempt to change it.
Set the `ClientMode` in your configuration profile to the integer value `1` for MONITOR or `2` for LOCKDOWN.
Change to Monitor mode:
```sh
sudo launchctl unload /Library/LaunchDaemons/com.google.santad.plist
sudo defaults write /var/db/santa/config.plist ClientMode -int 1
sudo launchctl load /Library/LaunchDaemons/com.google.santad.plist
```xml
<key>ClientMode</key>
<integer>1</integer>
```
Change to Lockdown mode:
Install your new configuration profile, it will overwrite any old `com.google.santa` profiles you may have already install. See the [configuration](../deployment/configuration.md) document for more details.
```sh
sudo launchctl unload /Library/LaunchDaemons/com.google.santad.plist
sudo defaults write /var/db/santa/config.plist ClientMode -int 2
sudo launchctl load /Library/LaunchDaemons/com.google.santad.plist
```
######Change modes with a sync server
###### Change modes with a sync server
The mode is set in the preflight sync stage. Use the key `client_mode` and a value of `MONITOR` or `LOCKDOWN`.

View File

@@ -5,16 +5,19 @@ inhibit_all_warnings!
target :Santa do
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'MOLXPCConnection'
end
target :santad do
pod 'FMDB'
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'MOLXPCConnection'
target :santabs do
pod 'FMDB'
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'MOLXPCConnection'
end
end
@@ -24,6 +27,7 @@ target :santactl do
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'MOLFCMClient', '~> 1.3'
pod 'MOLXPCConnection'
end
target :LogicTests do
@@ -31,6 +35,7 @@ target :LogicTests do
pod 'MOLAuthenticatingURLSession'
pod 'MOLCertificate'
pod 'MOLCodesignChecker'
pod 'MOLXPCConnection'
pod 'OCMock'
end

View File

@@ -1,15 +1,17 @@
PODS:
- FMDB (2.6.2):
- FMDB/standard (= 2.6.2)
- FMDB/standard (2.6.2)
- MOLAuthenticatingURLSession (2.2):
- MOLCertificate (~> 1.5)
- MOLCertificate (1.5)
- MOLCodesignChecker (1.5):
- MOLCertificate (~> 1.3)
- MOLFCMClient (1.3):
- MOLAuthenticatingURLSession (~> 2.1)
- OCMock (3.4)
- FMDB (2.7.2):
- FMDB/standard (= 2.7.2)
- FMDB/standard (2.7.2)
- MOLAuthenticatingURLSession (2.4):
- MOLCertificate (~> 1.8)
- MOLCertificate (1.8)
- MOLCodesignChecker (1.10):
- MOLCertificate (~> 1.8)
- MOLFCMClient (1.7):
- MOLAuthenticatingURLSession (~> 2.4)
- MOLXPCConnection (1.1):
- MOLCodesignChecker (~> 1.9)
- OCMock (3.4.1)
DEPENDENCIES:
- FMDB
@@ -17,16 +19,28 @@ DEPENDENCIES:
- MOLCertificate
- MOLCodesignChecker
- MOLFCMClient (~> 1.3)
- MOLXPCConnection
- OCMock
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- FMDB
- MOLAuthenticatingURLSession
- MOLCertificate
- MOLCodesignChecker
- MOLFCMClient
- MOLXPCConnection
- OCMock
SPEC CHECKSUMS:
FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a
MOLAuthenticatingURLSession: 5a5e31eb73248c3e92c79b9a285f031194e8404c
MOLCertificate: c39cae866d24d36fbc78032affff83d401b5384a
MOLCodesignChecker: fc9c64147811d7b0d0739127003e0630dff9213a
MOLFCMClient: 13d8b42db9d750e772f09cc38fc453922fece09f
OCMock: 35ae71d6a8fcc1b59434d561d1520b9dd4f15765
FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
MOLAuthenticatingURLSession: c238aa1c9a7b1077eb39a6f40204bfe76a7d204e
MOLCertificate: c999513316d511c69f290fbf313dfe8dca4ad592
MOLCodesignChecker: b0d5db9d2f9bd94e0fd093891a5d40e5ad77cbc0
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
MOLXPCConnection: de9d5535928f59766a768384e411077b83ec2f9c
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
PODFILE CHECKSUM: acd378b3727c923d912e09812da344f7375c14fe
PODFILE CHECKSUM: ddca043a7ace9ec600c108621c56d13a50d17236
COCOAPODS: 1.2.1
COCOAPODS: 1.5.3

View File

@@ -15,7 +15,7 @@ execution decisions based on the contents of a SQLite database, a GUI agent that
notifies the user in case of a block decision and a command-line utility for
managing the system and synchronizing the database with a server.
Santa is not yet a 1.0. We're writing more tests, fixing bugs, working on TODOs
Santa is not yet at 1.0. We're writing more tests, fixing bugs, working on TODOs
and finishing up a security audit.
It is named Santa because it keeps track of binaries that are naughty or nice.
@@ -29,21 +29,21 @@ The Santa docs are stored in the [Docs](https://github.com/google/santa/blob/mas
Admin-Related Features
========
* Multiple modes: In the default MONITOR mode, all binaries except
* Multiple modes: In the default MONITOR mode, all binaries except
those marked as blacklisted will be allowed to run, whilst being logged and recorded in the events database. In LOCKDOWN mode, only whitelisted binaries are
allowed to run.
* Event logging: When the kext is loaded, all binary launches are logged.
When in either mode, all unknown or denied binaries are stored in the database to enable later aggregation.
* Certificate-based rules, with override levels: Instead of relying on a binaries hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
* Certificate-based rules, with override levels: Instead of relying on a binary's hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
certificate. You can therefore trust/block all binaries by a given publisher that were signed with that cert across version updates. A
binary can only be whitelisted by its certificate if its signature validates
correctly, but a rule for a binaries fingerprint will override a decision for a
correctly, but a rule for a binary's fingerprint will override a decision for a
certificate; i.e. you can whitelist a certificate while blacklisting a binary
signed with that certificate, or vice-versa.
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature as Managed Client for OS X's (the precursor to configuration profiles, which used the same implementation mechanism) Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and doesn't rely on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precendence.
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature to that found in Managed Client (the precursor to configuration profiles, which used the same implementation mechanism), Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and not relying on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precedence.
* Failsafe cert rules: You cannot put in a deny rule that would block the certificate used to sign launchd, a.k.a. pid 1, and therefore all components used in macOS. The binaries in every OS update (and in some cases entire new versions) are therefore auto-whitelisted. This does not affect binaries from Apple's App Store, which use various certs that change regularly for common apps. Likewise, you cannot blacklist Santa itself, and Santa uses a distinct separate cert than other Google apps.
@@ -54,7 +54,7 @@ Santa is written with the intention of helping protect users from themselves.
People often download malware and trust it, giving the malware credentials, or
allowing unknown software to exfiltrate more data about your system. As a
centrally managed component, Santa can help stop the spread of malware among a
larger fleet of machines. Independently, Santa can aid in analyzing what is
large fleet of machines. Independently, Santa can aid in analyzing what is
running on your computer.
Santa is part of a defense-in-depth strategy, and you should continue to protect
@@ -62,7 +62,6 @@ hosts in whatever other ways you see fit.
Get Help
========
If you have questions or otherwise need help getting started, the
[santa-dev](https://groups.google.com/forum/#!forum/santa-dev) group is a
great place. Please consult the [wiki](https://github.com/google/santa/wiki) and [issues](https://github.com/google/santa/issues) as well.
@@ -84,7 +83,7 @@ continue to work across OS versions.
Known Issues
============
Santa is not yet a 1.0 and we have some known issues to be aware of:
Santa is not yet at 1.0 and we have some known issues to be aware of:
* Santa only blocks execution (execve and variants), it doesn't protect against
dynamic libraries loaded with dlopen, libraries on disk that have been replaced, or
@@ -99,11 +98,11 @@ only the root user can read/write it. We're considering approaches to secure
this further.
* Sync client: The `santactl` command-line client includes a flag to synchronize with a management server, which uploads events that have occurred on the
machine and downloads new rules. We're still very heavily working on this
server (which is AppEngine-based and will be open-sourced in the future), so the
sync client code is unfinished. It does show the 'API' that we're expecting to
use so if you'd like to write your own management server, feel free to look at
how the client currently works (and suggest changes!)
machine and downloads new rules. There are several open-source servers you can sync with:
* [Upvote](https://github.com/google/upvote) - An AppEngine-based server that implements social voting to make managing a large fleet easier.
* [Moroz](https://github.com/groob/moroz) - A simple golang server that serves hardcoded rules from simple configuration files.
* [Zentral](https://github.com/zentralopensource/zentral/wiki) - A centralized service that pulls data from multiple sources and deploy configurations to multiple services.
* Scripts: Santa is currently written to ignore any execution that isn't a
binary. This is because after weighing the administration cost vs the benefit,
@@ -127,8 +126,6 @@ A tool like Santa doesn't really lend itself to screenshots, so here's a video i
Building
========
Firstly, make sure you're using Xcode 7.3.1 as currently we do not support
building with Xcode 8.
```sh
git clone https://github.com/google/santa

View File

@@ -106,6 +106,7 @@ namespace :install do
system 'sudo cp conf/com.google.santad.plist /Library/LaunchDaemons'
system 'sudo cp conf/com.google.santagui.plist /Library/LaunchAgents'
system 'sudo cp conf/com.google.santa.asl.conf /etc/asl'
system 'sudo cp conf/com.google.santa.newsyslog.conf /etc/newsyslog.d/'
system '/usr/bin/killall -HUP syslogd'
Rake::Task['build:build'].invoke(config)
puts "Installing with configuration: #{config}"
@@ -154,20 +155,8 @@ namespace :tests do
desc "Tests: Kernel"
task :kernel do
Rake::Task['unload'].invoke()
Rake::Task['install:debug'].invoke()
Rake::Task['load_kext'].invoke
FileUtils.mkdir_p("/tmp/santa_kerneltests_tmp")
begin
puts "\033[?25l\033[12h" # hide cursor
puts "Running kernel tests"
system "cd /tmp/santa_kerneltests_tmp && sudo #{xcodebuilddir}/Debug/KernelTests"
rescue Exception
ensure
puts "\033[?25h\033[12l\n\n" # unhide cursor
FileUtils.rm_rf("/tmp/santa_kerneltests_tmp")
Rake::Task['unload_kext'].execute
end
Rake::Task['build:debug'].invoke()
system "sudo #{xcodebuilddir}/Debug/KernelTests"
end
end

View File

@@ -32,6 +32,7 @@
0D10BE861A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */; };
0D10BE871A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */; };
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */; };
0D10D18420C19445008251ED /* SNTCommandCacheHistogram.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D10D18320C19445008251ED /* SNTCommandCacheHistogram.m */; };
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */; };
0D1B477119A53419008CADD3 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D1B476F19A53419008CADD3 /* AboutWindow.xib */; };
0D202D191CDD2EE500A88F16 /* SNTCommandSyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D202D181CDD2EE500A88F16 /* SNTCommandSyncTest.m */; };
@@ -47,7 +48,6 @@
0D35BDA218FD71CE00921A21 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDA118FD71CE00921A21 /* main.m */; };
0D35BDAC18FD7CFD00921A21 /* SNTCommandController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */; };
0D35BDB518FD84F600921A21 /* SNTCommandSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDB418FD84F600921A21 /* SNTCommandSync.m */; };
0D35BDC418FDA5D100921A21 /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D377C2A17A071B7008453DB /* SNTEventTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D377C2917A071B7008453DB /* SNTEventTable.m */; };
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D37C10E18F6029A0069BC61 /* SNTDatabaseTable.m */; };
0D385DC4180DE4A900418BC6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D385DC3180DE4A900418BC6 /* main.m */; };
@@ -56,7 +56,6 @@
0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D385DEB180DE51600418BC6 /* SNTAppDelegate.m */; };
0D385DF2180DE51600418BC6 /* SNTMessageWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D385DED180DE51600418BC6 /* SNTMessageWindowController.m */; };
0D385DF3180DE51600418BC6 /* SNTNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D385DEF180DE51600418BC6 /* SNTNotificationManager.m */; };
0D3AFBE718FB32CB0087BCEE /* SNTXPCConnectionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */; };
0D3AFBEB18FB48E70087BCEE /* SNTDatabaseTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D37C10E18F6029A0069BC61 /* SNTDatabaseTable.m */; };
0D3AFBEC18FB48E70087BCEE /* SNTEventTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D377C2917A071B7008453DB /* SNTEventTable.m */; };
0D3AFBEE18FB4C6C0087BCEE /* SNTApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */; };
@@ -72,13 +71,9 @@
0D4644C6182AF81700098690 /* SantaDecisionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D4644C4182AF81700098690 /* SantaDecisionManager.h */; };
0D536ED71B8E7A2E0039A26D /* bad_pagezero in Resources */ = {isa = PBXBuildFile; fileRef = 0D536ED51B8E7A2E0039A26D /* bad_pagezero */; };
0D536ED81B8E7A2E0039A26D /* missing_pagezero in Resources */ = {isa = PBXBuildFile; fileRef = 0D536ED61B8E7A2E0039A26D /* missing_pagezero */; };
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D536EDC1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D668E8018D1121700E29A8B /* SNTMessageWindow.m */; };
0D6FDC9618C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D6FDC9718C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0D7D01871774F93A005DBAB4 /* SNTDriverManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */; };
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
0D827E6719DF3C74006EC811 /* SNTCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827E6619DF3C74006EC811 /* SNTCommandStatus.m */; };
@@ -111,7 +106,6 @@
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 /* SNTCommandFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD5FBE1909D64A006B445C /* SNTCommandFileInfo.m */; };
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
0DCD6043190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
@@ -148,10 +142,6 @@
0DEA5F7B1CF64C9200704398 /* sync_ruledownload_batch2.json in Resources */ = {isa = PBXBuildFile; fileRef = 0DEA5F781CF64C8B00704398 /* sync_ruledownload_batch2.json */; };
0DEA5F7D1CF64EB600704398 /* SNTCommandSyncRuleDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */; };
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */; };
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
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 */; };
168A4E09A2A5E0B7DF8A2F1A /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C11A10A5D6E112788769CF70 /* libPods-santad.a */; };
@@ -168,6 +158,12 @@
C7479F051E53704E0054C1CF /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; };
C7479F071E5374BF0054C1CF /* SNTXPCControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD605419115D17006B445C /* SNTXPCControlInterface.m */; };
C7479F091E5374E50054C1CF /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
C748E8A3206964E1006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; };
C748E8A4206964EE006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; };
C748E8A720696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; };
C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; };
C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; };
C748E8B120697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; };
C74D6CC61EEB3B9B00BB5A33 /* BundleExample.app in Resources */ = {isa = PBXBuildFile; fileRef = C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */; };
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */; };
C776A1071DEE160500A56616 /* SNTCommandSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C776A1061DEE160500A56616 /* SNTCommandSyncManager.m */; };
@@ -179,12 +175,12 @@
C7C721AE1E23FCB50051FAA6 /* SNTBundleService.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721AD1E23FCB50051FAA6 /* SNTBundleService.m */; };
C7C721B11E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; };
C7C721B21E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; };
C7C721B31E2400310051FAA6 /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
C7C721B41E24042B0051FAA6 /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
C7C721B51E2408BE0051FAA6 /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
C7C721B61E2408C30051FAA6 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA73C9E1934F8100056D7C4 /* SNTLogging.m */; };
C7DA62F71E241938009BDF2C /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; };
C7DA62F91E241A02009BDF2C /* SNTCommandBundleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DA62F81E241A02009BDF2C /* SNTCommandBundleInfo.m */; };
C7EAF71820A0A20B00745126 /* DirectoryBundle in Resources */ = {isa = PBXBuildFile; fileRef = C7EAF71720A0A20B00745126 /* DirectoryBundle */; };
C7FB56F61DBFB480004E14EF /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FB56F51DBFB480004E14EF /* SNTXPCSyncdInterface.m */; };
C7FB56F71DBFB480004E14EF /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FB56F51DBFB480004E14EF /* SNTXPCSyncdInterface.m */; };
C7FB57001DBFC213004E14EF /* SNTSyncdQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FB56FF1DBFC213004E14EF /* SNTSyncdQueue.m */; };
@@ -291,6 +287,7 @@
0D0A1EC5191AB9B000B8450F /* SNTCommandSyncPostflight.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncPostflight.m; sourceTree = "<group>"; };
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDropRootPrivs.m; sourceTree = "<group>"; };
0D10BE881A0AAC2100C0C944 /* SNTDropRootPrivs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTDropRootPrivs.h; sourceTree = "<group>"; };
0D10D18320C19445008251ED /* SNTCommandCacheHistogram.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCacheHistogram.m; sourceTree = "<group>"; };
0D1B476D19A53419008CADD3 /* SNTAboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTAboutWindowController.h; sourceTree = "<group>"; };
0D1B476E19A53419008CADD3 /* SNTAboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTAboutWindowController.m; sourceTree = "<group>"; };
0D1B476F19A53419008CADD3 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindow.xib; sourceTree = "<group>"; };
@@ -328,7 +325,6 @@
0D385DED180DE51600418BC6 /* SNTMessageWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTMessageWindowController.m; sourceTree = "<group>"; };
0D385DEE180DE51600418BC6 /* SNTNotificationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTNotificationManager.h; sourceTree = "<group>"; };
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 /* 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>"; };
@@ -345,14 +341,10 @@
0D5058CF1CB70123008784BA /* SNTStrengthify.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTStrengthify.h; sourceTree = "<group>"; };
0D536ED51B8E7A2E0039A26D /* bad_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = bad_pagezero; sourceTree = "<group>"; };
0D536ED61B8E7A2E0039A26D /* missing_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = missing_pagezero; sourceTree = "<group>"; };
0D536ED91B94E9230039A26D /* SNTEventLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
0D536EDA1B94E9230039A26D /* SNTEventLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
0D63DD5A1906FCB400D346C4 /* SNTDatabaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDatabaseController.h; sourceTree = "<group>"; };
0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDatabaseController.m; sourceTree = "<group>"; };
0D668E7F18D1121700E29A8B /* SNTMessageWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTMessageWindow.h; sourceTree = "<group>"; };
0D668E8018D1121700E29A8B /* SNTMessageWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTMessageWindow.m; sourceTree = "<group>"; };
0D6FDC9418C93A020044685C /* SNTXPCConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTXPCConnection.h; sourceTree = "<group>"; };
0D6FDC9518C93A020044685C /* SNTXPCConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCConnection.m; sourceTree = "<group>"; };
0D7D01851774F93A005DBAB4 /* SNTDriverManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDriverManager.h; sourceTree = "<group>"; };
0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = SNTDriverManager.m; sourceTree = "<group>"; };
0D827E6619DF3C74006EC811 /* SNTCommandStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandStatus.m; sourceTree = "<group>"; };
@@ -415,9 +407,6 @@
0DEA5F781CF64C8B00704398 /* sync_ruledownload_batch2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = sync_ruledownload_batch2.json; sourceTree = "<group>"; };
0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncConstants.m; sourceTree = "<group>"; };
0DEFB7C11ACB28BC00B92AAE /* SNTCommandSyncConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncConstants.h; sourceTree = "<group>"; };
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTFileWatcher.h; sourceTree = "<group>"; };
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcher.m; sourceTree = "<group>"; };
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTFileWatcherTest.m; sourceTree = "<group>"; };
0DF395621AB76A7900CBC520 /* NSData+Zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Zlib.h"; sourceTree = "<group>"; };
0DF395631AB76A7900CBC520 /* NSData+Zlib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Zlib.m"; sourceTree = "<group>"; };
0DF395651AB76ABC00CBC520 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
@@ -436,6 +425,12 @@
A6A91785C40257CC156B4F05 /* Pods-Santa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.release.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.release.xcconfig"; sourceTree = "<group>"; };
C11A10A5D6E112788769CF70 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
C72E8D931D7F399900C86DD3 /* SNTCommandFileInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandFileInfoTest.m; sourceTree = "<group>"; };
C748E8A1206964DE006CFD1B /* SNTEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
C748E8A2206964DE006CFD1B /* SNTEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
C748E8A520696594006CFD1B /* SNTFileEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTFileEventLog.h; sourceTree = "<group>"; };
C748E8A620696595006CFD1B /* SNTFileEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTFileEventLog.m; sourceTree = "<group>"; };
C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSyslogEventLog.h; sourceTree = "<group>"; };
C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTSyslogEventLog.m; sourceTree = "<group>"; };
C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = BundleExample.app; sourceTree = "<group>"; };
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCheckCache.m; sourceTree = "<group>"; };
C776A1051DEE160500A56616 /* SNTCommandSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncManager.h; sourceTree = "<group>"; };
@@ -450,6 +445,7 @@
C7C721AF1E23FF300051FAA6 /* SNTXPCBundleServiceInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTXPCBundleServiceInterface.h; sourceTree = "<group>"; };
C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCBundleServiceInterface.m; sourceTree = "<group>"; };
C7DA62F81E241A02009BDF2C /* SNTCommandBundleInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandBundleInfo.m; sourceTree = "<group>"; };
C7EAF71720A0A20B00745126 /* DirectoryBundle */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DirectoryBundle; sourceTree = "<group>"; };
C7FB56F41DBFB480004E14EF /* SNTXPCSyncdInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTXPCSyncdInterface.h; sourceTree = "<group>"; };
C7FB56F51DBFB480004E14EF /* SNTXPCSyncdInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCSyncdInterface.m; sourceTree = "<group>"; };
C7FB56FE1DBFC213004E14EF /* SNTSyncdQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTSyncdQueue.h; sourceTree = "<group>"; };
@@ -539,9 +535,7 @@
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */,
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
);
path = LogicTests;
sourceTree = "<group>";
@@ -549,6 +543,7 @@
0D260DB018B68E12002A0B55 /* Resources */ = {
isa = PBXGroup;
children = (
C7EAF71720A0A20B00745126 /* DirectoryBundle */,
C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */,
0D536ED51B8E7A2E0039A26D /* bad_pagezero */,
0D2CD4601A81C7B100C9C910 /* dn.plist */,
@@ -732,8 +727,6 @@
0D10BE851A0AABD600C0C944 /* SNTDropRootPrivs.m */,
0DCD6040190ACCB8006B445C /* SNTFileInfo.h */,
0DCD6041190ACCB8006B445C /* SNTFileInfo.m */,
0DEFB7C21ACDD80100B92AAE /* SNTFileWatcher.h */,
0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */,
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */,
0D28E5E119269B3600280F87 /* SNTLogging.h */,
0DA73C9E1934F8100056D7C4 /* SNTLogging.m */,
@@ -746,8 +739,6 @@
0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */,
C7C721AF1E23FF300051FAA6 /* SNTXPCBundleServiceInterface.h */,
C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */,
0D6FDC9418C93A020044685C /* SNTXPCConnection.h */,
0D6FDC9518C93A020044685C /* SNTXPCConnection.m */,
0DCD605319115D17006B445C /* SNTXPCControlInterface.h */,
0DCD605419115D17006B445C /* SNTXPCControlInterface.m */,
0DC8C9E3180CC3BC00FCFB29 /* SNTXPCNotifierInterface.h */,
@@ -762,6 +753,7 @@
isa = PBXGroup;
children = (
0DA73CA519363C9F0056D7C4 /* DataLayer */,
C748E8A020696001006CFD1B /* Logs */,
0D9A7F411759330500035EB5 /* main.m */,
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */,
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */,
@@ -775,8 +767,6 @@
C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */,
0D7D01851774F93A005DBAB4 /* SNTDriverManager.h */,
0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */,
0D536ED91B94E9230039A26D /* SNTEventLog.h */,
0D536EDA1B94E9230039A26D /* SNTEventLog.m */,
0DE6788B1784A8C2007A9E52 /* SNTExecutionController.h */,
0DE6788C1784A8C2007A9E52 /* SNTExecutionController.m */,
0DE5B5491C926E3300C00603 /* SNTNotificationQueue.h */,
@@ -813,6 +803,7 @@
isa = PBXGroup;
children = (
C7DA62F81E241A02009BDF2C /* SNTCommandBundleInfo.m */,
0D10D18320C19445008251ED /* SNTCommandCacheHistogram.m */,
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */,
0DCD5FBE1909D64A006B445C /* SNTCommandFileInfo.m */,
0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */,
@@ -850,6 +841,19 @@
name = Frameworks;
sourceTree = "<group>";
};
C748E8A020696001006CFD1B /* Logs */ = {
isa = PBXGroup;
children = (
C748E8A1206964DE006CFD1B /* SNTEventLog.h */,
C748E8A2206964DE006CFD1B /* SNTEventLog.m */,
C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */,
C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */,
C748E8A520696594006CFD1B /* SNTFileEventLog.h */,
C748E8A620696595006CFD1B /* SNTFileEventLog.m */,
);
path = Logs;
sourceTree = "<group>";
};
C79A23541E23F7E80037AFA8 /* santabs */ = {
isa = PBXGroup;
children = (
@@ -928,8 +932,6 @@
0D260DA818B68E12002A0B55 /* Sources */,
0D260DA918B68E12002A0B55 /* Frameworks */,
0D260DAA18B68E12002A0B55 /* Resources */,
D49A3AB950AFD99741E9AF89 /* [CP] Embed Pods Frameworks */,
23869BA352E2C86DEFE62819 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -948,7 +950,6 @@
0DD98E671A5DD02000A754C6 /* Update Version Info */,
0D35BD9A18FD71CE00921A21 /* Sources */,
0D35BD9B18FD71CE00921A21 /* Frameworks */,
2737FE8516A33567D3449943 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -968,8 +969,6 @@
0D385DB2180DE4A900418BC6 /* Sources */,
0D385DB3180DE4A900418BC6 /* Frameworks */,
0D385DB4180DE4A900418BC6 /* Resources */,
BA20035148DDEF5808B2C7EF /* [CP] Embed Pods Frameworks */,
DDE76075391100F3BCE3634E /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1011,7 +1010,6 @@
0DD98E661A5DCED300A754C6 /* Update Version Info */,
0D9A7F391759330400035EB5 /* Sources */,
0D9A7F3A1759330400035EB5 /* Frameworks */,
531BBB5BA4BF953D628D29AB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1032,7 +1030,6 @@
C78227501E1C3C58006EB2D6 /* Sources */,
C78227511E1C3C58006EB2D6 /* Frameworks */,
C78227521E1C3C58006EB2D6 /* Resources */,
FCF4BDAA180BD63C32AC85DE /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1049,7 +1046,7 @@
0D91BCA8174E8A6500131A7D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
LastUpgradeCheck = 0910;
TargetAttributes = {
0D260DAB18B68E12002A0B55 = {
TestTargetID = 0D385DB5180DE4A900418BC6;
@@ -1097,6 +1094,7 @@
0D2CD4611A81C7B100C9C910 /* dn.plist in Resources */,
0DEA5F7B1CF64C9200704398 /* sync_ruledownload_batch2.json in Resources */,
0DEA5F6C1CF6254900704398 /* sync_preflight_lockdown.json in Resources */,
C7EAF71820A0A20B00745126 /* DirectoryBundle in Resources */,
0D536ED81B8E7A2E0039A26D /* missing_pagezero in Resources */,
0D202D201CE4E90E00A88F16 /* sync_preflight_basic.json in Resources */,
);
@@ -1221,13 +1219,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-santad-santabs-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
2146C1274A8C11B3755A8A67 /* [CP] Check Pods Manifest.lock */ = {
@@ -1236,58 +1237,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-santad-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
23869BA352E2C86DEFE62819 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
2737FE8516A33567D3449943 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santactl/Pods-santactl-resources.sh\"\n";
showEnvVarsInLog = 0;
};
531BBB5BA4BF953D628D29AB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santad/Pods-santad-resources.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9BF8830B1029605A497F13D5 /* [CP] Check Pods Manifest.lock */ = {
@@ -1296,13 +1255,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-LogicTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
B193461D3612BCB47C16E407 /* [CP] Check Pods Manifest.lock */ = {
@@ -1311,28 +1273,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Santa-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
BA20035148DDEF5808B2C7EF /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-frameworks.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C7F95F971E23F9E7007A6BF5 /* Update bundle version */ = {
@@ -1358,58 +1308,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-santactl-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
D49A3AB950AFD99741E9AF89 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
DDE76075391100F3BCE3634E /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FCF4BDAA180BD63C32AC85DE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santad-santabs/Pods-santad-santabs-resources.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -1432,15 +1340,15 @@
C7DA62F71E241938009BDF2C /* SNTXPCBundleServiceInterface.m in Sources */,
C714F8B11D8044D400700EDF /* SNTCommandFileInfo.m in Sources */,
0D88680C1AC48A1400B86659 /* SNTSystemInfo.m in Sources */,
0D536EDC1B94E9230039A26D /* SNTEventLog.m in Sources */,
0DEA5F7D1CF64EB600704398 /* SNTCommandSyncRuleDownload.m in Sources */,
C748E8A4206964EE006CFD1B /* SNTEventLog.m in Sources */,
C748E8B120697F01006CFD1B /* SNTSyslogEventLog.m in Sources */,
C73A4B9B1DC10758007B6789 /* SNTXPCSyncdInterface.m in Sources */,
0DB77FDB1CD14093004DF060 /* SNTBlockMessage.m in Sources */,
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
0D202D191CDD2EE500A88F16 /* SNTCommandSyncTest.m in Sources */,
0D3AFBF018FB4C6C0087BCEE /* SNTDriverManager.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 */,
@@ -1450,15 +1358,13 @@
0DCD605819115E57006B445C /* SNTXPCControlInterface.m in Sources */,
0D202D1A1CDD464B00A88F16 /* SNTCommandSyncPreflight.m in Sources */,
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */,
0DEFB7C61ACDE5F600B92AAE /* SNTFileWatcher.m in Sources */,
C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */,
C72E8D941D7F399900C86DD3 /* SNTCommandFileInfoTest.m in Sources */,
0DEFB7C81ACF0BFE00B92AAE /* SNTFileWatcherTest.m in Sources */,
C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */,
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */,
0DE5B54C1C92722300C00603 /* SNTNotificationQueue.m in Sources */,
0DEA5F651CF6057D00704398 /* SNTCommandSyncEventUpload.m in Sources */,
0DB77FFB1CD7AC5A004DF060 /* SNTCommandSyncConstants.m in Sources */,
0D3AFBE718FB32CB0087BCEE /* SNTXPCConnectionTest.m in Sources */,
0D9184B91CD2F32D0004E859 /* SNTCommandSyncStage.m in Sources */,
0DCD605719115E54006B445C /* SNTDaemonControlController.m in Sources */,
0D2E1E631CEFA6C30039B2C4 /* SantaCacheTest.mm in Sources */,
@@ -1488,9 +1394,9 @@
0DE50F6C19130358007B2B0C /* SNTStoredEvent.m in Sources */,
0D9184B81CD2F32D0004E859 /* SNTCommandSyncStage.m in Sources */,
C776A1071DEE160500A56616 /* SNTCommandSyncManager.m in Sources */,
0D35BDC418FDA5D100921A21 /* SNTXPCConnection.m in Sources */,
0DCD605C19117A90006B445C /* SNTCommandSyncPreflight.m in Sources */,
0D41640519197AD7006A356A /* SNTCommandSyncEventUpload.m in Sources */,
0D10D18420C19445008251ED /* SNTCommandCacheHistogram.m in Sources */,
0D42D2B919D2042900955F08 /* SNTConfigurator.m in Sources */,
0DF395641AB76A7900CBC520 /* NSData+Zlib.m in Sources */,
C7FB56F71DBFB480004E14EF /* SNTXPCSyncdInterface.m in Sources */,
@@ -1518,7 +1424,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */,
0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */,
0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */,
0D89310F1C931986002E8D74 /* SNTRule.m in Sources */,
@@ -1532,7 +1437,6 @@
0D1B477019A53419008CADD3 /* SNTAboutWindowController.m in Sources */,
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */,
0DA73CA11934F8100056D7C4 /* SNTLogging.m in Sources */,
0DEFB7C51ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
C7479F051E53704E0054C1CF /* SNTXPCBundleServiceInterface.m in Sources */,
0D20710E1A7C4A86008B0A9A /* SNTStoredEvent.m in Sources */,
0DE2CE561CA05561002B649A /* SNTAccessibleTextField.m in Sources */,
@@ -1556,6 +1460,7 @@
0D8868091AC48A1100B86659 /* SNTSystemInfo.m in Sources */,
0DE6788D1784A8C2007A9E52 /* SNTExecutionController.m in Sources */,
0D10BE861A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */,
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
0DCD604B19105433006B445C /* SNTStoredEvent.m in Sources */,
C7FB57001DBFC213004E14EF /* SNTSyncdQueue.m in Sources */,
@@ -1566,19 +1471,18 @@
0DE71A751B95F7F900518526 /* SNTCachedDecision.m in Sources */,
C7FB56F61DBFB480004E14EF /* SNTXPCSyncdInterface.m in Sources */,
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */,
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */,
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */,
0D7D01871774F93A005DBAB4 /* SNTDriverManager.m in Sources */,
0D8E18CD19107B56000F89B8 /* SNTDaemonControlController.m in Sources */,
0D6FDC9618C93A020044685C /* SNTXPCConnection.m in Sources */,
0D377C2A17A071B7008453DB /* SNTEventTable.m in Sources */,
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */,
0DB77FD81CCE824A004DF060 /* SNTBlockMessage.m in Sources */,
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */,
C748E8A720696595006CFD1B /* SNTFileEventLog.m in Sources */,
C748E8A3206964E1006CFD1B /* SNTEventLog.m in Sources */,
0D42D2B819D2042900955F08 /* SNTConfigurator.m in Sources */,
0DCD605519115D17006B445C /* SNTXPCControlInterface.m in Sources */,
C795ED901D80A5BE007CFF42 /* SNTPolicyProcessor.m in Sources */,
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */,
0DCD604F19115A06006B445C /* SNTXPCNotifierInterface.m in Sources */,
0DE5B54B1C926E3300C00603 /* SNTNotificationQueue.m in Sources */,
);
@@ -1589,7 +1493,6 @@
buildActionMask = 2147483647;
files = (
C7C721B21E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m in Sources */,
C7C721B31E2400310051FAA6 /* SNTXPCConnection.m in Sources */,
C7C721B61E2408C30051FAA6 /* SNTLogging.m in Sources */,
C7C721B41E24042B0051FAA6 /* SNTStoredEvent.m in Sources */,
C7C721B51E2408BE0051FAA6 /* SNTFileInfo.m in Sources */,
@@ -1681,6 +1584,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
OTHER_CODE_SIGN_FLAGS = "";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fcxx-modules",
@@ -1715,6 +1619,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
OTHER_CODE_SIGN_FLAGS = "";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fcxx-modules",
@@ -1975,11 +1880,34 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LLVM_LTO = NO;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
@@ -2003,13 +1931,37 @@
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
OTHER_CODE_SIGN_FLAGS = "-o library,kill";
PROVISIONING_PROFILE = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = macosx;
@@ -2025,6 +1977,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_CODE_COVERAGE = NO;
CLANG_ENABLE_MODULES = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_CONSTANT_CONVERSION = YES;
@@ -2063,6 +2016,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_CODE_COVERAGE = NO;
CLANG_ENABLE_MODULES = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_CONSTANT_CONVERSION = YES;

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -48,6 +48,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -45,6 +46,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
debugAsWhichUser = "root"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@@ -55,6 +56,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -46,6 +47,7 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
debugAsWhichUser = "root"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16F73" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<development version="6300" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<capability name="system font weights other than Regular or Bold" minToolsVersion="7.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SNTMessageWindowController">
@@ -22,13 +23,14 @@
<window title="Santa Blocked Execution" 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="540" height="479"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<rect key="screenRect" x="0.0" y="0.0" width="3840" height="1578"/>
<view key="contentView" id="Iwq-Lx-rLv">
<rect key="frame" x="0.0" y="0.0" width="540" height="479"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kiB-jZ-69S">
<rect key="frame" x="16" y="451" width="37" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Hidden Button" alternateTitle="This button exists so neither of the other two buttons is pre-selected when the dialog opens." bezelStyle="rounded" alignment="center" borderStyle="border" focusRingType="none" transparent="YES" imageScaling="proportionallyDown" inset="2" id="XGa-Sl-F4t">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@@ -40,20 +42,6 @@
<outlet property="nextKeyView" destination="7ua-5a-uSd" id="vl5-A8-O0H"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="t8c-Fx-e5h">
<rect key="frame" x="228" y="408" width="85" height="41"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" sendsActionOnEndEditing="YES" title="Santa" id="7YA-iB-Zma">
<font key="font" metaFont="systemUltraLight" size="34"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="accessibilityElement" value="NO"/>
</userDefinedRuntimeAttributes>
</textFieldCell>
<connections>
<outlet property="nextKeyView" destination="7ua-5a-uSd" id="z5y-RR-IEH"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cD5-Su-lXR" customClass="SNTAccessibleTextField">
<rect key="frame" x="43" y="369" width="454" height="17"/>
<constraints>
@@ -370,7 +358,7 @@ DQ
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<box horizontalHuggingPriority="750" title="Line" boxType="custom" borderType="line" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="4Li-ul-zIi">
<box horizontalHuggingPriority="750" boxType="custom" borderType="line" title="Line" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="4Li-ul-zIi">
<rect key="frame" x="168" y="132" width="1" height="207"/>
<constraints>
<constraint firstAttribute="width" constant="1" id="0o1-Jh-epf"/>
@@ -418,6 +406,20 @@ DQ
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="t8c-Fx-e5h">
<rect key="frame" x="229" y="408" width="82" height="41"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" sendsActionOnEndEditing="YES" title="Santa" id="7YA-iB-Zma">
<font key="font" metaFont="systemUltraLight" size="34"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="accessibilityElement" value="NO"/>
</userDefinedRuntimeAttributes>
</textFieldCell>
<connections>
<outlet property="nextKeyView" destination="7ua-5a-uSd" id="z5y-RR-IEH"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="oFj-ol-xpL" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" constant="10" id="0AD-PS-5V1"/>

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
@interface SNTAboutWindowController : NSWindowController

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
/**
An NSTextField subclass that provides an accessiblity label equal to:

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
///
/// Initiates and manages the connection to santad

View File

@@ -14,20 +14,19 @@
#import "SNTAppDelegate.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTAboutWindowController.h"
#import "SNTConfigurator.h"
#import "SNTFileWatcher.h"
#import "SNTNotificationManager.h"
#import "SNTStrengthify.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTAppDelegate ()
@property SNTAboutWindowController *aboutWindowController;
@property SNTFileWatcher *configFileWatcher;
@property SNTNotificationManager *notificationManager;
@property SNTXPCConnection *daemonListener;
@property SNTXPCConnection *bundleListener;
@property MOLXPCConnection *daemonListener;
@property MOLXPCConnection *bundleListener;
@end
@implementation SNTAppDelegate
@@ -36,12 +35,6 @@
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self setupMenu];
self.configFileWatcher = [[SNTFileWatcher alloc] initWithFilePath:kMobileConfigFilePath
handler:^(unsigned long data) {
if (!(data & DISPATCH_VNODE_ATTRIB)) [[SNTConfigurator configurator] reloadConfigData];
}];
self.notificationManager = [[SNTNotificationManager alloc] init];
NSNotificationCenter *workspaceNotifications = [[NSWorkspace sharedWorkspace] notificationCenter];
@@ -53,12 +46,17 @@
self.daemonListener.invalidationHandler = nil;
[self.daemonListener invalidate];
self.daemonListener = nil;
self.bundleListener.invalidationHandler = nil;
[self.bundleListener invalidate];
self.bundleListener = nil;
}];
[workspaceNotifications addObserverForName:NSWorkspaceSessionDidBecomeActiveNotification
object:nil
queue:[NSOperationQueue currentQueue]
usingBlock:^(NSNotification *note) {
[self attemptDaemonReconnection];
[self attemptBundleReconnection];
}];
[self createDaemonConnection];
@@ -80,7 +78,7 @@
// Create listener for return connection from daemon.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.daemonListener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.daemonListener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.daemonListener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
self.daemonListener.exportedObject = self.notificationManager;
self.daemonListener.acceptedHandler = ^{
@@ -93,9 +91,10 @@
[self.daemonListener resume];
// Tell daemon to connect back to the above listener.
SNTXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
[daemonConn resume];
[[daemonConn remoteObjectProxy] setNotificationListener:listener.endpoint];
[daemonConn invalidate];
// Now wait for the connection to come in.
if (dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC))) {
@@ -104,6 +103,8 @@
}
- (void)attemptDaemonReconnection {
self.daemonListener.invalidationHandler = nil;
[self.daemonListener invalidate];
[self performSelectorInBackground:@selector(createDaemonConnection) withObject:nil];
}
@@ -114,7 +115,7 @@
// Create listener for return connection from the bundle service.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.bundleListener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.bundleListener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.bundleListener.exportedInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
self.bundleListener.exportedObject = self.notificationManager;
self.bundleListener.acceptedHandler = ^{
@@ -127,9 +128,10 @@
[self.bundleListener resume];
// Tell santabs to connect back to the above listener.
SNTXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
[daemonConn resume];
[[daemonConn remoteObjectProxy] setBundleNotificationListener:listener.endpoint];
[daemonConn invalidate];
// Now wait for the connection to come in.
if (dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC))) {
@@ -138,6 +140,8 @@
}
- (void)attemptBundleReconnection {
self.bundleListener.invalidationHandler = nil;
[self.bundleListener invalidate];
[self performSelectorInBackground:@selector(createBundleConnection) withObject:nil];
}

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
///
/// An NSPanel that can become key/main and can fade in/out.

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
@class SNTStoredEvent;

View File

@@ -14,12 +14,12 @@
#import "SNTMessageWindowController.h"
@import SecurityInterface.SFCertificatePanel;
#import <SecurityInterface/SFCertificatePanel.h>
#import <MOLCertificate/MOLCertificate.h>
#import "MOLCertificate.h"
#import "SNTBlockMessage.h"
#import "SNTConfigurator.h"
#import "SNTFileInfo.h"
#import "SNTMessageWindow.h"
#import "SNTStoredEvent.h"

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
#import "SNTMessageWindowController.h"
#import "SNTXPCNotifierInterface.h"

View File

@@ -14,12 +14,13 @@
#import "SNTNotificationManager.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTBlockMessage.h"
#import "SNTConfigurator.h"
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
#import "SNTStrengthify.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTNotificationManager ()
@@ -31,7 +32,7 @@
@property(readonly) NSMutableArray *pendingNotifications;
/// The connection to the bundle service
@property SNTXPCConnection *bundleServiceConnection;
@property MOLXPCConnection *bundleServiceConnection;
/// A semaphore to block bundle hashing until a connection is established
@property dispatch_semaphore_t bundleServiceSema;
@@ -102,14 +103,16 @@ static NSString * const silencedNotificationsKey = @"SilencedNotifications";
case SNTClientModeMonitor:
un.informativeText = @"Switching into Monitor mode";
customMsg = [[SNTConfigurator configurator] modeNotificationMonitor];
customMsg = [SNTBlockMessage stringFromHTML:customMsg];
if (customMsg.length) un.informativeText = customMsg;
if (!customMsg) break;
if (!customMsg.length) return;
un.informativeText = [SNTBlockMessage stringFromHTML:customMsg];
break;
case SNTClientModeLockdown:
un.informativeText = @"Switching into Lockdown mode";
customMsg = [[SNTConfigurator configurator] modeNotificationLockdown];
customMsg = [SNTBlockMessage stringFromHTML:customMsg];
if (customMsg.length) un.informativeText = customMsg;
if (!customMsg) break;
if (!customMsg.length) return;
un.informativeText = [SNTBlockMessage stringFromHTML:customMsg];
break;
default:
return;
@@ -190,7 +193,7 @@ static NSString * const silencedNotificationsKey = @"SilencedNotifications";
}
- (void)setBundleServiceListener:(NSXPCListenerEndpoint *)listener {
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
MOLXPCConnection *c = [[MOLXPCConnection alloc] initClientWithListener:listener];
c.remoteInterface = [SNTXPCBundleServiceInterface bundleServiceInterface];
[c resume];
self.bundleServiceConnection = c;
@@ -201,6 +204,8 @@ static NSString * const silencedNotificationsKey = @"SilencedNotifications";
if (self.currentWindowController) {
[self updateBlockNotification:self.currentWindowController.event withBundleHash:nil];
}
self.bundleServiceConnection.invalidationHandler = nil;
[self.bundleServiceConnection invalidate];
};
dispatch_semaphore_signal(self.bundleServiceSema);
@@ -243,9 +248,10 @@ static NSString * const silencedNotificationsKey = @"SilencedNotifications";
}
// Send the results to santad. It will decide if they need to be synced.
SNTXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
[daemonConn resume];
[[daemonConn remoteObjectProxy] syncBundleEvent:event relatedEvents:events];
[daemonConn invalidate];
// Update the UI with the bundle hash. Also make the openEventButton available.
[self updateBlockNotification:event withBundleHash:bh];

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Cocoa;
#import <Cocoa/Cocoa.h>
#import "SNTAppDelegate.h"

View File

@@ -13,9 +13,9 @@
/// limitations under the License.
#ifdef SANTAGUI
@import Cocoa;
#import <Cocoa/Cocoa.h>
#else
@import Foundation;
#import <Foundation/Foundation.h>
#endif
@class SNTStoredEvent;

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
///
/// These enums are used in various places throughout the Santa client code.
@@ -80,6 +80,12 @@ typedef NS_ENUM(NSInteger, SNTBundleEventAction) {
SNTBundleEventActionSendEvents,
};
// Indicates where to store event logs.
typedef NS_ENUM(NSInteger, SNTEventLogType) {
SNTEventLogTypeSyslog,
SNTEventLogTypeFilelog,
};
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";

View File

@@ -12,16 +12,14 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"
extern NSString *const kSyncStateFilePath;
extern NSString *const kMobileConfigFilePath;
///
/// 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.
/// @note All properties are KVO compliant.
///
@interface SNTConfigurator : NSObject
@@ -30,16 +28,12 @@ extern NSString *const kMobileConfigFilePath;
///
/// The operating mode.
///
@property(nonatomic) SNTClientMode clientMode;
@property(readonly, nonatomic) SNTClientMode clientMode;
///
/// The regex of paths to log file changes for. Regexes are specified in ICU format.
/// Set the operating mode as received from a sync server.
///
/// 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 *fileChangesRegex;
- (void)setSyncServerClientMode:(SNTClientMode)newMode;
///
/// The regex of whitelisted paths. Regexes are specified in ICU format.
@@ -48,7 +42,12 @@ extern NSString *const kMobileConfigFilePath;
/// 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;
@property(readonly, nonatomic) NSRegularExpression *whitelistPathRegex;
///
/// Set the regex of whitelisted paths as received from a sync server.
///
- (void)setSyncServerWhitelistPathRegex:(NSRegularExpression *)re;
///
/// The regex of blacklisted paths. Regexes are specified in ICU format.
@@ -57,7 +56,21 @@ extern NSString *const kMobileConfigFilePath;
/// 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 *blacklistPathRegex;
@property(readonly, nonatomic) NSRegularExpression *blacklistPathRegex;
///
/// Set the regex of blacklisted paths as received from a sync server.
///
- (void)setSyncServerBlacklistPathRegex:(NSRegularExpression *)re;
///
/// The regex of paths to log file changes for. 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(readonly, nonatomic) NSRegularExpression *fileChangesRegex;
///
/// Enable __PAGEZERO protection, defaults to YES
@@ -66,6 +79,32 @@ extern NSString *const kMobileConfigFilePath;
///
@property(readonly, nonatomic) BOOL enablePageZeroProtection;
///
/// Defines how event logs are stored. Options are:
/// SNTEventLogTypeSyslog: Sent to ASL or ULS (if built with the 10.12 SDK or later).
/// SNTEventLogTypeFilelog: Sent to a file on disk. Use eventLogPath to specify a path.
/// Defaults to SNTEventLogTypeFilelog.
/// For mobileconfigs use EventLogType as the key and syslog or filelog strings as the value.
///
/// @note: This property is KVO compliant, but should only be read once at santad startup.
///
@property(readonly, nonatomic) SNTEventLogType eventLogType;
///
/// If eventLogType is set to Filelog, eventLogPath will provide the path to save logs.
/// Defaults to /var/db/santa/santa.log.
///
/// @note: This property is KVO compliant, but should only be read once at santad startup.
///
@property(readonly, nonatomic) NSString *eventLogPath;
///
/// Enabling this appends the Santa machine ID to the end of each log line. If nothing
/// has been overriden, this is the host's UUID.
/// Defaults to NO.
///
@property(readonly, nonatomic) BOOL enableMachineIDDecoration;
#pragma mark - GUI Settings
///
@@ -202,13 +241,8 @@ extern NSString *const kMobileConfigFilePath;
+ (instancetype)configurator;
///
/// Re-read config data from disk.
/// Clear the sync server configuration from the effective configuration.
///
- (void)reloadConfigData;
///
/// Notify the receiver that the sync state file has changed.
///
- (void)syncStateFileChanged:(unsigned long)data;
- (void)clearSyncState;
@end

View File

@@ -17,22 +17,20 @@
#include <sys/stat.h>
#import "SNTLogging.h"
#import "SNTStrengthify.h"
#import "SNTSystemInfo.h"
@interface SNTConfigurator ()
@property NSMutableDictionary *configData;
/// Creating NSRegularExpression objects is not fast, so cache them.
@property NSRegularExpression *cachedFileChangesRegex;
@property NSRegularExpression *cachedWhitelistDirRegex;
@property NSRegularExpression *cachedBlacklistDirRegex;
/// A NSUserDefaults object set to use the com.google.santa suite.
@property(readonly, nonatomic) NSUserDefaults *defaults;
/// Keys used by a mobileconfig or sync server
@property(readonly, nonatomic) NSArray *syncServerKeys;
@property(readonly, nonatomic) NSArray *mobileConfigKeys;
// Keys and expected value types.
@property(readonly, nonatomic) NSDictionary *syncServerKeyTypes;
@property(readonly, nonatomic) NSDictionary *forcedConfigKeyTypes;
/// Holds the configurations from a sync server and mobileconfig.
@property NSMutableDictionary *syncState;
@property NSMutableDictionary *configState;
@end
@implementation SNTConfigurator
@@ -43,9 +41,6 @@ NSString *const kSyncStateFilePath = @"/var/db/santa/sync-state.plist";
/// The domain used by mobileconfig.
static NSString *const kMobileConfigDomain = @"com.google.santa";
/// The hard-coded path to the mobileconfig file.
NSString *const kMobileConfigFilePath = @"/Library/Managed Preferences/com.google.santa.plist";
/// The keys managed by a mobileconfig.
static NSString *const kSyncBaseURLKey = @"SyncBaseURL";
static NSString *const kClientAuthCertificateFileKey = @"ClientAuthCertificateFile";
@@ -72,11 +67,17 @@ static NSString *const kModeNotificationLockdown = @"ModeNotificationLockdown";
static NSString *const kEnablePageZeroProtectionKey = @"EnablePageZeroProtection";
static NSString *const kFileChangesRegexKey = @"FileChangesRegex";
static NSString *const kEventLogType = @"EventLogType";
static NSString *const kEventLogPath = @"EventLogPath";
static NSString *const kEnableMachineIDDecoration = @"EnableMachineIDDecoration";
// The keys managed by a sync server or mobileconfig.
static NSString *const kClientModeKey = @"ClientMode";
static NSString *const kWhitelistRegexKey = @"WhitelistRegex";
static NSString *const kBlacklistRegexKey = @"BlacklistRegex";
static NSString *const kFileChangesRegexKey = @"FileChangesRegex";
// The keys managed by a sync server.
static NSString *const kFullSyncLastSuccess = @"FullSyncLastSuccess";
@@ -86,22 +87,54 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
- (instancetype)init {
self = [super init];
if (self) {
_defaults = [[NSUserDefaults alloc] initWithSuiteName:kMobileConfigDomain];
_syncServerKeys = @[
kClientModeKey, kWhitelistRegexKey, kBlacklistRegexKey, kFileChangesRegexKey,
kFullSyncLastSuccess, kRuleSyncLastSuccess, kSyncCleanRequired
];
_mobileConfigKeys = @[
kClientModeKey, kFileChangesRegexKey, kWhitelistRegexKey, kBlacklistRegexKey,
kEnablePageZeroProtectionKey, kMoreInfoURLKey, kEventDetailURLKey, kEventDetailTextKey,
kUnknownBlockMessage, kBannedBlockMessage, kModeNotificationMonitor,
kModeNotificationLockdown, kSyncBaseURLKey, kClientAuthCertificateFileKey,
kClientAuthCertificatePasswordKey, kClientAuthCertificateCNKey,
kClientAuthCertificateIssuerKey, kServerAuthRootsDataKey, kServerAuthRootsFileKey,
kMachineOwnerKey, kMachineIDKey, kMachineOwnerPlistFileKey, kMachineOwnerPlistKeyKey,
kMachineIDPlistFileKey, kMachineIDPlistKeyKey
];
[self reloadConfigData];
Class number = [NSNumber class];
Class re = [NSRegularExpression class];
Class date = [NSDate class];
Class string = [NSString class];
Class data = [NSData class];
_syncServerKeyTypes = @{
kClientModeKey : number,
kWhitelistRegexKey : re,
kBlacklistRegexKey : re,
kFullSyncLastSuccess : date,
kRuleSyncLastSuccess : date,
kSyncCleanRequired : number
};
_forcedConfigKeyTypes = @{
kClientModeKey : number,
kFileChangesRegexKey : re,
kWhitelistRegexKey : re,
kBlacklistRegexKey : re,
kEnablePageZeroProtectionKey : number,
kMoreInfoURLKey : string,
kEventDetailURLKey : string,
kEventDetailTextKey : string,
kUnknownBlockMessage : string,
kBannedBlockMessage : string,
kModeNotificationMonitor : string,
kModeNotificationLockdown : string,
kSyncBaseURLKey : string,
kClientAuthCertificateFileKey : string,
kClientAuthCertificatePasswordKey : string,
kClientAuthCertificateCNKey : string,
kClientAuthCertificateIssuerKey : string,
kServerAuthRootsDataKey : data,
kServerAuthRootsFileKey : string,
kMachineOwnerKey : string,
kMachineIDKey : string,
kMachineOwnerPlistFileKey : string,
kMachineOwnerPlistKeyKey : string,
kMachineIDPlistFileKey : string,
kMachineIDPlistKeyKey : string,
kEventLogType : string,
kEventLogPath : string,
kEnableMachineIDDecoration : number,
};
_defaults = [NSUserDefaults standardUserDefaults];
[_defaults addSuiteNamed:@"com.google.santa"];
_configState = [self readForcedConfig];
_syncState = [self readSyncStateFromDisk] ?: [NSMutableDictionary dictionary];
[self startWatchingDefaults];
}
return self;
}
@@ -117,277 +150,352 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return sharedConfigurator;
}
+ (NSSet *)syncAndConfigStateSet {
static NSSet *set;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
set = [[self syncStateSet] setByAddingObjectsFromSet:[self configStateSet]];
});
return set;
}
+ (NSSet *)syncStateSet {
static NSSet *set;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
set = [NSSet setWithObject:NSStringFromSelector(@selector(syncState))];
});
return set;
}
+ (NSSet *)configStateSet {
static NSSet *set;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
set = [NSSet setWithObject:NSStringFromSelector(@selector(configState))];
});
return set;
}
#pragma mark KVO Dependencies
+ (NSSet *)keyPathsForValuesAffectingClientMode {
return [self syncAndConfigStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingWhitelistPathRegex {
return [self syncAndConfigStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingBlacklistPathRegex {
return [self syncAndConfigStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingFileChangesRegex {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncBaseURL {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnablePageZeroProtection {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingMoreInfoURL {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventDetailURL {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventDetailText {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingUnknownBlockMessage {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingBannedBlockMessage {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingModeNotificationMonitor {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingModeNotificationLockdown {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateFile {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificatePassword {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateCn {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateIssuer {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsData {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsFile {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingMachineOwner {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingMachineID {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingFullSyncLastSuccess {
return [self syncStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingRuleSyncLastSuccess {
return [self syncStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingSyncCleanRequired {
return [self syncStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventLogType {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventLogPath {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableMachineIDDecoration {
return [self configStateSet];
}
#pragma mark Public Interface
- (SNTClientMode)clientMode {
NSInteger cm = SNTClientModeUnknown;
id mode = self.configData[kClientModeKey];
if ([mode respondsToSelector:@selector(longLongValue)]) {
cm = (NSInteger)[mode longLongValue];
}
SNTClientMode cm = [self.syncState[kClientModeKey] longLongValue];
if (cm == SNTClientModeMonitor || cm == SNTClientModeLockdown) {
return (SNTClientMode)cm;
} else {
LOGE(@"Client mode was set to bad value: %ld. Resetting to MONITOR.", cm);
self.clientMode = SNTClientModeMonitor;
return SNTClientModeMonitor;
return cm;
}
cm = [self.configState[kClientModeKey] longLongValue];
if (cm == SNTClientModeMonitor || cm == SNTClientModeLockdown) {
return cm;
}
return SNTClientModeMonitor;
}
- (void)setClientMode:(SNTClientMode)newMode {
- (void)setSyncServerClientMode:(SNTClientMode)newMode {
if (newMode == SNTClientModeMonitor || newMode == SNTClientModeLockdown) {
self.configData[kClientModeKey] = @(newMode);
[self saveSyncStateToDisk];
[self updateSyncStateForKey:kClientModeKey value:@(newMode)];
} else {
LOGW(@"Ignoring request to change client mode to %ld", newMode);
}
}
- (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:NULL];
}
return self.cachedWhitelistDirRegex;
return self.syncState[kWhitelistRegexKey] ?: self.configState[kWhitelistRegexKey];
}
- (void)setWhitelistPathRegex:(NSRegularExpression *)re {
if (!re) {
[self.configData removeObjectForKey:kWhitelistRegexKey];
} else {
self.configData[kWhitelistRegexKey] = [re pattern];
}
self.cachedWhitelistDirRegex = nil;
[self saveSyncStateToDisk];
- (void)setSyncServerWhitelistPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kWhitelistRegexKey value:re];
}
- (NSRegularExpression *)blacklistPathRegex {
if (!self.cachedBlacklistDirRegex && self.configData[kBlacklistRegexKey]) {
NSString *re = self.configData[kBlacklistRegexKey];
if (![re hasPrefix:@"^"]) re = [@"^" stringByAppendingString:re];
self.cachedBlacklistDirRegex = [NSRegularExpression regularExpressionWithPattern:re
options:0
error:NULL];
}
return self.cachedBlacklistDirRegex;
return self.syncState[kBlacklistRegexKey] ?: self.configState[kBlacklistRegexKey];
}
- (void)setBlacklistPathRegex:(NSRegularExpression *)re {
if (!re) {
[self.configData removeObjectForKey:kBlacklistRegexKey];
} else {
self.configData[kBlacklistRegexKey] = [re pattern];
}
self.cachedBlacklistDirRegex = nil;
[self saveSyncStateToDisk];
- (void)setSyncServerBlacklistPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kBlacklistRegexKey value:re];
}
- (NSRegularExpression *)fileChangesRegex {
if (!self.cachedFileChangesRegex && self.configData[kFileChangesRegexKey]) {
NSString *re = self.configData[kFileChangesRegexKey];
if (![re hasPrefix:@"^"]) re = [@"^" stringByAppendingString:re];
self.cachedFileChangesRegex = [NSRegularExpression regularExpressionWithPattern:re
options:0
error:NULL];
}
return self.cachedFileChangesRegex;
}
- (void)setFileChangesRegex:(NSRegularExpression *)re {
if (!re) {
[self.configData removeObjectForKey:kFileChangesRegexKey];
} else {
self.configData[kFileChangesRegexKey] = [re pattern];
}
self.cachedFileChangesRegex = nil;
[self saveSyncStateToDisk];
}
- (BOOL)enablePageZeroProtection {
NSNumber *keyValue = self.configData[kEnablePageZeroProtectionKey];
return keyValue ? [keyValue boolValue] : YES;
}
- (NSURL *)moreInfoURL {
return [NSURL URLWithString:self.configData[kMoreInfoURLKey]];
}
- (NSString *)eventDetailURL {
return self.configData[kEventDetailURLKey];
}
- (NSString *)eventDetailText {
return self.configData[kEventDetailTextKey];
}
- (NSString *)unknownBlockMessage {
return self.configData[kUnknownBlockMessage];
}
- (NSString *)bannedBlockMessage {
return self.configData[kBannedBlockMessage];
}
- (NSString *)modeNotificationMonitor {
return self.configData[kModeNotificationMonitor];
}
- (NSString *)modeNotificationLockdown {
return self.configData[kModeNotificationLockdown];
return self.configState[kFileChangesRegexKey];
}
- (NSURL *)syncBaseURL {
NSString *urlStr = self.configData[kSyncBaseURLKey];
if (urlStr) {
NSURL *url = [NSURL URLWithString:urlStr];
if (!url) LOGW(@"SyncBaseURL is not a valid URL!");
return url;
}
return nil;
NSString *urlString = self.configState[kSyncBaseURLKey];
NSURL *url = [NSURL URLWithString:urlString];
if (urlString && !url) LOGW(@"SyncBaseURL is not a valid URL!");
return url;
}
- (BOOL)enablePageZeroProtection {
NSNumber *number = self.configState[kEnablePageZeroProtectionKey];
return number ? [number boolValue] : YES;
}
- (NSURL *)moreInfoURL {
return [NSURL URLWithString:self.configState[kMoreInfoURLKey]];
}
- (NSString *)eventDetailURL {
return self.configState[kEventDetailURLKey];
}
- (NSString *)eventDetailText {
return self.configState[kEventDetailTextKey];
}
- (NSString *)unknownBlockMessage {
return self.configState[kUnknownBlockMessage];
}
- (NSString *)bannedBlockMessage {
return self.configState[kBannedBlockMessage];
}
- (NSString *)modeNotificationMonitor {
return self.configState[kModeNotificationMonitor];
}
- (NSString *)modeNotificationLockdown {
return self.configState[kModeNotificationLockdown];
}
- (NSString *)syncClientAuthCertificateFile {
return self.configData[kClientAuthCertificateFileKey];
return self.configState[kClientAuthCertificateFileKey];
}
- (NSString *)syncClientAuthCertificatePassword {
return self.configData[kClientAuthCertificatePasswordKey];
return self.configState[kClientAuthCertificatePasswordKey];
}
- (NSString *)syncClientAuthCertificateCn {
return self.configData[kClientAuthCertificateCNKey];
return self.configState[kClientAuthCertificateCNKey];
}
- (NSString *)syncClientAuthCertificateIssuer {
return self.configData[kClientAuthCertificateIssuerKey];
return self.configState[kClientAuthCertificateIssuerKey];
}
- (NSData *)syncServerAuthRootsData {
return self.configData[kServerAuthRootsDataKey];
return self.configState[kServerAuthRootsDataKey];
}
- (NSString *)syncServerAuthRootsFile {
return self.configData[kServerAuthRootsFileKey];
return self.configState[kServerAuthRootsFileKey];
}
- (NSDate *)fullSyncLastSuccess {
return self.configData[kFullSyncLastSuccess];
return self.syncState[kFullSyncLastSuccess];
}
- (void)setFullSyncLastSuccess:(NSDate *)fullSyncLastSuccess {
self.configData[kFullSyncLastSuccess] = fullSyncLastSuccess;
[self saveSyncStateToDisk];
[self updateSyncStateForKey:kFullSyncLastSuccess value:fullSyncLastSuccess];
self.ruleSyncLastSuccess = fullSyncLastSuccess;
}
- (NSDate *)ruleSyncLastSuccess {
return self.configData[kRuleSyncLastSuccess];
return self.syncState[kRuleSyncLastSuccess];
}
- (void)setRuleSyncLastSuccess:(NSDate *)ruleSyncLastSuccess {
self.configData[kRuleSyncLastSuccess] = ruleSyncLastSuccess;
[self saveSyncStateToDisk];
[self updateSyncStateForKey:kRuleSyncLastSuccess value:ruleSyncLastSuccess];
}
- (BOOL)syncCleanRequired {
return [self.configData[kSyncCleanRequired] boolValue];
return [self.syncState[kSyncCleanRequired] boolValue];
}
- (void)setSyncCleanRequired:(BOOL)syncCleanRequired {
self.configData[kSyncCleanRequired] = @(syncCleanRequired);
[self saveSyncStateToDisk];
[self updateSyncStateForKey:kSyncCleanRequired value:@(syncCleanRequired)];
}
- (NSString *)machineOwner {
NSString *machineOwner;
NSString *machineOwner = self.configState[kMachineOwnerKey];
if (machineOwner) return machineOwner;
if (self.configData[kMachineOwnerPlistFileKey] && self.configData[kMachineOwnerPlistKeyKey]) {
NSDictionary *plist =
[NSDictionary dictionaryWithContentsOfFile:self.configData[kMachineOwnerPlistFileKey]];
machineOwner = plist[self.configData[kMachineOwnerPlistKeyKey]];
NSString *plistPath = self.configState[kMachineOwnerPlistFileKey];
NSString *plistKey = self.configState[kMachineOwnerPlistKeyKey];
if (plistPath && plistKey) {
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistPath];
machineOwner = [plist[plistKey] isKindOfClass:[NSString class]] ? plist[plistKey] : nil;
}
if (self.configData[kMachineOwnerKey]) {
machineOwner = self.configData[kMachineOwnerKey];
}
if (!machineOwner) machineOwner = @"";
return machineOwner;
return machineOwner ?: @"";
}
- (NSString *)machineID {
NSString *machineId;
NSString *machineId = self.configState[kMachineIDKey];
if (machineId) return machineId;
if (self.configData[kMachineIDPlistFileKey] && self.configData[kMachineIDPlistKeyKey]) {
NSDictionary *plist =
[NSDictionary dictionaryWithContentsOfFile:self.configData[kMachineIDPlistFileKey]];
machineId = plist[self.configData[kMachineIDPlistKeyKey]];
NSString *plistPath = self.configState[kMachineIDPlistFileKey];
NSString *plistKey = self.configState[kMachineIDPlistKeyKey];
if (plistPath && plistKey) {
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistPath];
machineId = [plist[plistKey] isKindOfClass:[NSString class]] ? plist[plistKey] : nil;
}
if (self.configData[kMachineIDKey]) {
machineId = self.configData[kMachineIDKey];
}
if ([machineId length] == 0) {
machineId = [SNTSystemInfo hardwareUUID];
}
return machineId;
return machineId.length ? machineId : [SNTSystemInfo hardwareUUID];
}
- (void)reloadConfigData {
// Load the mobileconfig
self.configData = [self mobileConfig];
if (!self.configData[kClientModeKey]) {
// Default to Monitor if the config is missing or invalid
self.configData[kClientModeKey] = @(SNTClientModeMonitor);
}
- (SNTEventLogType)eventLogType {
NSString *s = [self.configState[kEventLogType] lowercaseString];
return [s isEqualToString:@"syslog"] ? SNTEventLogTypeSyslog : SNTEventLogTypeFilelog;
}
// Nothing else to do if a sync server is not involved
if (!self.configData[kSyncBaseURLKey]) return;
- (NSString *)eventLogPath {
return self.configState[kEventLogPath] ?: @"/var/db/santa/santa.log";
}
// Load the last known sync state
if (![[NSFileManager defaultManager] fileExistsAtPath:kSyncStateFilePath]) return;
NSMutableDictionary *syncState = [self syncState];
if (!self) return;
// Overwrite or add the sync state to the running config
for (NSString *key in [self syncServerKeys]) {
self.configData[key] = syncState[key];
}
[self saveSyncStateToDisk];
- (BOOL)enableMachineIDDecoration {
NSNumber *number = self.configState[kEnableMachineIDDecoration];
return number ? [number boolValue] : NO;
}
#pragma mark Private
- (NSMutableDictionary *)syncState {
NSError *error;
NSData *readData = [NSData dataWithContentsOfFile:kSyncStateFilePath
options:NSDataReadingMappedIfSafe
error:&error];
if (!readData) {
LOGE(@"Could not read sync state file: %@, replacing.", [error localizedDescription]);
///
/// Update the syncState. Triggers a KVO event for all dependents.
///
- (void)updateSyncStateForKey:(NSString *)key value:(id)value {
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableDictionary *syncState = self.syncState.mutableCopy;
syncState[key] = value;
self.syncState = syncState;
[self saveSyncStateToDisk];
return nil;
}
});
}
///
/// Read the saved syncState.
///
- (NSMutableDictionary *)readSyncStateFromDisk {
// Only read the sync state if a sync server is configured.
if (!self.syncBaseURL) return nil;
// Only santad should read this file.
if (geteuid() != 0) return nil;
NSMutableDictionary *syncState =
[NSPropertyListSerialization propertyListWithData:readData
options:NSPropertyListMutableContainers
format:NULL
error:&error];
if (!syncState) {
LOGE(@"Could not parse sync state file: %@, replacing.", [error localizedDescription]);
[self saveSyncStateToDisk];
return nil;
[NSMutableDictionary dictionaryWithContentsOfFile:kSyncStateFilePath];
for (NSString *key in syncState.allKeys) {
if (self.syncServerKeyTypes[key] == [NSRegularExpression class]) {
NSString *pattern = [syncState[key] isKindOfClass:[NSString class]] ? syncState[key] : nil;
syncState[key] = [self expressionForPattern:pattern];
} else if (![syncState[key] isKindOfClass:self.syncServerKeyTypes[key]]) {
syncState[key] = nil;
continue;
}
}
return syncState;
}
@@ -395,71 +503,70 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
/// Saves the current effective syncState to disk.
///
- (void)saveSyncStateToDisk {
// Only save the sync state if a sync server is configured.
if (!self.syncBaseURL) return;
// Only santad should write to this file.
if (geteuid() != 0) return;
NSMutableDictionary *syncState =
[NSMutableDictionary dictionaryWithCapacity:[self syncServerKeys].count];
for (NSString *key in [self syncServerKeys]) {
syncState[key] = self.configData[key];
}
// Either remove
NSMutableDictionary *syncState = self.syncState.mutableCopy;
syncState[kWhitelistRegexKey] = [syncState[kWhitelistRegexKey] pattern];
syncState[kBlacklistRegexKey] = [syncState[kBlacklistRegexKey] pattern];
[syncState writeToFile:kSyncStateFilePath atomically:YES];
[[NSFileManager defaultManager] setAttributes:@{ NSFilePosixPermissions : @0644 }
ofItemAtPath:kSyncStateFilePath error:NULL];
}
///
/// Ensure permissions are 0644.
/// Revert any out-of-band changes.
///
- (void)syncStateFileChanged:(unsigned long)data {
if (data & DISPATCH_VNODE_ATTRIB) {
const char *cPath = [kSyncStateFilePath fileSystemRepresentation];
struct stat fileStat;
stat(cPath, &fileStat);
int mask = S_IRWXU | S_IRWXG | S_IRWXO;
int desired = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (fileStat.st_uid != 0 || fileStat.st_gid != 0 || (fileStat.st_mode & mask) != desired) {
LOGD(@"Sync state file permissions changed, fixing.");
chown(cPath, 0, 0);
chmod(cPath, desired);
}
} else {
NSDictionary *syncState = [self syncState];
for (NSString *key in self.syncServerKeys) {
if (((self.configData[key] && !syncState[key]) ||
(!self.configData[key] && syncState[key]) ||
(self.configData[key] && ![self.configData[key] isEqualTo:syncState[key]]))) {
// Ignore sync url and dates
if ([key isEqualToString:kSyncBaseURLKey] ||
[key isEqualToString:kRuleSyncLastSuccess] ||
[key isEqualToString:kFullSyncLastSuccess]) continue;
LOGE(@"Sync state file changed, replacing");
[self saveSyncStateToDisk];
return;
}
- (void)clearSyncState {
self.syncState = [NSMutableDictionary dictionary];
}
#pragma mark Private Defaults Methods
- (NSRegularExpression *)expressionForPattern:(NSString *)pattern {
if (!pattern) return nil;
if (![pattern hasPrefix:@"^"]) pattern = [@"^" stringByAppendingString:pattern];
return [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
}
- (NSMutableDictionary *)readForcedConfig {
NSMutableDictionary *forcedConfig = [NSMutableDictionary dictionary];
for (NSString *key in self.forcedConfigKeyTypes) {
id obj = [self forcedConfigValueForKey:key];
forcedConfig[key] = [obj isKindOfClass:self.forcedConfigKeyTypes[key]] ? obj : nil;
// Create the regex objects now
if (self.forcedConfigKeyTypes[key] == [NSRegularExpression class]) {
NSString *pattern = [obj isKindOfClass:[NSString class]] ? obj : nil;
forcedConfig[key] = [self expressionForPattern:pattern];
}
}
return forcedConfig;
}
- (id)forcedConfigValueForKey:(NSString *)key {
id obj = [self.defaults objectForKey:key];
return [self.defaults objectIsForcedForKey:key inDomain:kMobileConfigDomain] ? obj : nil;
}
- (void)startWatchingDefaults {
// Only santad should listen.
if (geteuid() != 0) return;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(defaultsChanged:)
name:NSUserDefaultsDidChangeNotification
object:nil];
}
- (void)defaultsChanged:(void *)v {
SEL handleChange = @selector(handleChange);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:handleChange object:nil];
[self performSelector:handleChange withObject:nil afterDelay:5.0f];
}
///
/// Returns a config provided by a com.google.santa mobileconfig or an empty
/// NSMutableDictionary object if no config applies.
/// Update the configState. Triggers a KVO event for all dependents.
///
- (NSMutableDictionary *)mobileConfig {
NSMutableDictionary *config =
[NSMutableDictionary dictionaryWithCapacity:[self mobileConfigKeys].count];
for (NSString *key in [self mobileConfigKeys]) {
if ([self.defaults objectIsForcedForKey:key]) {
config[key] = [self.defaults objectForKey:key];
}
}
if (config[kSyncBaseURLKey]) {
for (NSString *key in [self syncServerKeys]) {
if ([key isEqualToString:kSyncBaseURLKey]) continue;
[config removeObjectForKey:key];
}
}
return config;
- (void)handleChange {
self.configState = [self readForcedConfig];
}
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
///
/// Simple function to check and drop root privileges.

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
@class MOLCodesignChecker;
@@ -212,6 +212,11 @@
///
- (NSUInteger)fileSize;
///
/// @return The underlying file handle.
///
@property(readonly) NSFileHandle *fileHandle;
///
/// @return Returns an instance of MOLCodeSignChecker initialized with the file's binary path.
/// Both the MOLCodesignChecker and any resulting NSError are cached and returned on subsequent

View File

@@ -17,13 +17,14 @@
#import <CommonCrypto/CommonDigest.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#import <FMDB/FMDB.h>
#import <fmdb/FMDB.h>
// Simple class to hold the data of a mach_header and the offset within the file
// in which that header was found.
@@ -287,7 +288,8 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
- (BOOL)isMissingPageZero {
// This method only checks i386 arch because the kernel enforces this for other archs
// See bsd/kern/mach_loader.c, search for enforce_hard_pagezero.
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86]];
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86
cpuSubType:CPU_SUBTYPE_I386_ALL]];
if (!x86Header) return NO;
struct mach_header *mh = (struct mach_header *)[x86Header.data bytes];
@@ -315,6 +317,26 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
#pragma mark Bundle Information
///
/// Directories with a "Contents/Info.plist" entry can be mistaken as a bundle. To be considered an
/// ancestor, the bundle must have a valid extension.
///
- (NSSet *)allowedAncestorExtensions {
static NSSet *set;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
set = [NSSet setWithArray:@[
@"app",
@"bundle",
@"framework",
@"kext",
@"xctest",
@"xpc",
]];
});
return set;
}
///
/// Try and determine the bundle that the represented executable is contained within, if any.
///
@@ -325,18 +347,21 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
///
/// This method walks up the path until a bundle is found, if any.
///
/// @param ancestor YES this will return the highest NSBundle found in the tree. No will return the
/// the lowest.
/// @param ancestor YES this will return the highest NSBundle, with a valid extension, found in the
/// tree. NO will return the the lowest NSBundle, without validating the extension.
///
-(NSBundle *)findBundleWithAncestor:(BOOL)ancestor {
- (NSBundle *)findBundleWithAncestor:(BOOL)ancestor {
NSBundle *bundle;
NSMutableArray *pathComponents = [[self.path pathComponents] mutableCopy];
// Ignore the root path "/", for some reason this is considered a bundle.
while (pathComponents.count > 1) {
NSBundle *bndl = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
if (bndl && [bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) {
bundle = bndl;
if ([bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) {
if (!ancestor ||
[[self allowedAncestorExtensions] containsObject:bndl.bundlePath.pathExtension]) {
bundle = bndl;
}
if (!ancestor) break;
}
[pathComponents removeLastObject];
@@ -443,7 +468,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
if (machHeader) {
struct mach_header *mh = (struct mach_header *)[machHeader bytes];
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader offset:0];
machHeaders[[self nameForCPUType:mh->cputype]] = mhwo;
machHeaders[[self nameForCPUType:mh->cputype cpuSubType:mh->cpusubtype]] = mhwo;
} else {
NSRange range = NSMakeRange(0, sizeof(struct fat_header));
NSData *fatHeader = [self safeSubdataWithRange:range];
@@ -459,11 +484,12 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
int offset = OSSwapBigToHostInt32(fat_arch[i].offset);
int size = OSSwapBigToHostInt32(fat_arch[i].size);
int cputype = OSSwapBigToHostInt(fat_arch[i].cputype);
int cpusubtype = OSSwapBigToHostInt(fat_arch[i].cpusubtype);
range = NSMakeRange(offset, size);
NSData *machHeader = [self parseSingleMachHeader:[self safeSubdataWithRange:range]];
if (machHeader) {
NSString *key = [self nameForCPUType:cputype];
NSString *key = [self nameForCPUType:cputype cpuSubType:cpusubtype];
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader
offset:offset];
machHeaders[key] = mhwo;
@@ -647,20 +673,15 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
///
/// Return a human-readable string for a cpu_type_t.
///
- (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";
- (NSString *)nameForCPUType:(cpu_type_t)cpuType cpuSubType:(cpu_subtype_t)cpuSubType {
const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cpuType, cpuSubType);
NSString *arch;
if (archInfo && archInfo->name) {
arch = @(archInfo->name);
} else {
arch = [NSString stringWithFormat:@"%i:%i", cpuType, cpuSubType];
}
return nil;
return arch;
}
///

View File

@@ -1,35 +0,0 @@
/// Copyright 2015 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
///
/// Simple file watching class using dispatch sources. Will automatically
/// reload the watch if the file is deleted and continue watching for
/// events until deallocated.
///
@interface SNTFileWatcher : NSObject
///
/// Designated initializer
/// Initializes the watcher and begins watching for modifications.
///
/// @param filePath the file to watch.
/// @param handler the handler to call when changes happen. The argument to the block is the
/// type of change that happened as a bitmask to be compared with DISPATCH_VNODE_* constants.
///
- (nonnull instancetype)initWithFilePath:(nonnull NSString *)filePath
handler:(nonnull void (^)(unsigned long))handler;
@end

View File

@@ -1,94 +0,0 @@
/// Copyright 2015 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
#import "SNTFileWatcher.h"
#import "SNTStrengthify.h"
@interface SNTFileWatcher ()
@property NSString *filePath;
@property(copy) void (^handler)(unsigned long);
@property dispatch_source_t source;
@end
@implementation SNTFileWatcher
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithFilePath:(nonnull NSString *)filePath
handler:(nonnull void (^)(unsigned long))handler {
self = [super init];
if (self) {
_filePath = filePath;
_handler = handler;
[self startWatchingFile];
}
return self;
}
- (void)dealloc {
[self stopWatchingFile];
}
- (void)startWatchingFile {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
int mask = (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME |
DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB);
dispatch_async(queue, ^{
int fd = -1;
const char *filePath = [self.filePath fileSystemRepresentation];
while ((fd = open(filePath, O_EVTONLY | O_CLOEXEC)) < 0) {
usleep(200000); // wait 200ms
}
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, mask, queue);
WEAKIFY(self);
dispatch_source_set_event_handler(self.source, ^{
STRONGIFY(self);
unsigned long data = dispatch_source_get_data(self.source);
self.handler(data);
if (data & DISPATCH_VNODE_DELETE || data & DISPATCH_VNODE_RENAME) {
[self stopWatchingFile];
[self startWatchingFile];
}
sleep(2);
});
dispatch_source_set_registration_handler(self.source, ^{
STRONGIFY(self);
self.handler(0);
});
dispatch_source_set_cancel_handler(self.source, ^{
close(fd);
});
dispatch_resume(self.source);
});
}
- (void)stopWatchingFile {
if (!self.source) return;
dispatch_source_set_event_handler_f(self.source, NULL);
dispatch_source_cancel(self.source);
self.source = nil;
}
@end

View File

@@ -21,9 +21,6 @@
#ifndef SANTA__COMMON__KERNELCOMMON_H
#define SANTA__COMMON__KERNELCOMMON_H
// 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"
#define USERCLIENT_ID "com.google.santa-driver"
@@ -37,9 +34,11 @@ enum SantaDriverMethods {
kSantaUserClientOpen,
kSantaUserClientAllowBinary,
kSantaUserClientDenyBinary,
kSantaUserClientAcknowledgeBinary,
kSantaUserClientClearCache,
kSantaUserClientCacheCount,
kSantaUserClientCheckCache,
kSantaUserClientCacheBucketCount,
// Any methods supported by the driver should be added above this line to
// ensure this remains the count of methods.
@@ -64,6 +63,7 @@ typedef enum {
ACTION_RESPOND_ALLOW = 20,
ACTION_RESPOND_DENY = 21,
ACTION_RESPOND_TOOLONG = 22,
ACTION_RESPOND_ACK = 23,
// NOTIFY
ACTION_NOTIFY_EXEC = 30,
@@ -80,10 +80,27 @@ typedef enum {
#define RESPONSE_VALID(x) \
(x == ACTION_RESPOND_ALLOW || x == ACTION_RESPOND_DENY)
// Struct to manage vnode IDs
typedef struct santa_vnode_id_t {
uint64_t fsid;
uint64_t fileid;
#ifdef __cplusplus
bool operator==(const santa_vnode_id_t& rhs) const {
return fsid == rhs.fsid && fileid == rhs.fileid;
}
// This _must not_ be used for anything security-sensitive. It exists solely to make
// the msleep/wakeup calls easier.
uint64_t unsafe_simple_id() const {
return (((uint64_t)fsid << 32) | fileid);
}
#endif
} santa_vnode_id_t;
// Message struct that is sent down the IODataQueue.
typedef struct {
santa_action_t action;
uint64_t vnode_id;
santa_vnode_id_t vnode_id;
uid_t uid;
gid_t gid;
pid_t pid;
@@ -97,4 +114,10 @@ typedef struct {
char pname[MAXPATHLEN];
} santa_message_t;
// Used for the kSantaUserClientCacheBucketCount request.
typedef struct {
uint16_t per_bucket[1024];
uint64_t start;
} santa_bucket_count_t;
#endif // SANTA__COMMON__KERNELCOMMON_H

View File

@@ -34,7 +34,7 @@
#else // KERNEL
@import Foundation;
#import <Foundation/Foundation.h>
typedef enum : NSUInteger {
LOG_LEVEL_ERROR,

View File

@@ -29,12 +29,12 @@ void syslogClientDestructor(void *arg) {
void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
static BOOL useSyslog = NO;
static const char *binaryName;
static NSString *binaryName;
static dispatch_once_t pred;
static pthread_key_t syslogKey = 0;
dispatch_once(&pred, ^{
binaryName = [[[NSProcessInfo processInfo] processName] UTF8String];
binaryName = [[NSProcessInfo processInfo] processName];
// If debug logging is enabled, the process must be restarted.
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--debug"]) {
@@ -76,7 +76,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
break;
case LOG_LEVEL_INFO:
levelName = "I";
syslogLevel = ASL_LEVEL_INFO;
syslogLevel = ASL_LEVEL_NOTICE; // Maps to ULS Default
break;
case LOG_LEVEL_DEBUG:
levelName = "D";
@@ -84,7 +84,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
break;
}
asl_log(client, NULL, syslogLevel, "%s %s: %s", levelName, binaryName, [s UTF8String]);
asl_log(client, NULL, syslogLevel, "%s %s: %s", levelName, binaryName.UTF8String, s.UTF8String);
} else {
[s appendString:@"\n"];
size_t len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding];

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"

View File

@@ -32,6 +32,8 @@
#pragma mark NSSecureCoding
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-literal-conversion"
#define ENCODE(obj, key) if (obj) [coder encodeObject:obj forKey:key]
#define DECODE(cls, key) [decoder decodeObjectOfClass:[cls class] forKey:key]
@@ -59,6 +61,7 @@
#undef DECODE
#undef ENCODE
#pragma clang diagnostic pop
- (BOOL)isEqual:(id)other {
if (other == self) return YES;

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"

View File

@@ -14,10 +14,13 @@
#import "SNTStoredEvent.h"
#import "MOLCertificate.h"
#import <MOLCertificate/MOLCertificate.h>
@implementation SNTStoredEvent
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-literal-conversion"
#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) \
@@ -129,4 +132,6 @@
[NSString stringWithFormat:@"SNTStoredEvent[%@] with SHA-256: %@", self.idx, self.fileSHA256];
}
#pragma clang diagnostic pop
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
///
/// Simple class for fetching system information

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
@class SNTStoredEvent;

View File

@@ -1,135 +0,0 @@
/// Copyright 2015 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
/**
A wrapper around NSXPCListener and NSXPCConnection to provide client multiplexing, signature
validation of connecting clients and forced connection establishment.
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 resume];
@endcode
Example client, connecting to above server:
@code
SNTXPCConnection *conn = [[SNTXPCConnection alloc] initClientWithName:"MyServer"
withOptions:0];
conn.remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyServerProtocol)];
conn.invalidationHandler = ^{ NSLog(@"Connection invalidated") };
[conn resume];
@endcode
The client can send a message to the server with:
@code
[conn.remoteObjectProxy selectorInRemoteInterface];
@endcode
One advantage of the way that SNTXPCConnection works over using NSXPCConnection directly is that
from the client-side once the resume method has finished, the connection is either valid or the
invalidation handler will be called. Ordinarily, the connection doesn't actually get made until
the first message is sent across it.
@note messages are always delivered on a background thread!
*/
@interface SNTXPCConnection : NSObject<NSXPCListenerDelegate>
/**
Initialize a new server with a given listener, provided by `[NSXPCListener anonymousListener]`.
*/
- (nullable instancetype)initServerWithListener:(nonnull NSXPCListener *)listener;
/**
Initializer for the 'server' side of the connection, started by launchd.
@param name MachService name, must match the MachServices key in the launchd.plist
*/
- (nullable instancetype)initServerWithName:(nonnull NSString *)name;
/**
Initialize a new client to a service exported by a LaunchDaemon.
@param name MachService name
@param privileged Use YES if the server is running as root.
*/
- (nullable instancetype)initClientWithName:(nonnull NSString *)name privileged:(BOOL)privileged;
/**
Initialize a new client to a service within a bundle.
@param name service name
*/
- (nullable instancetype)initClientWithServiceName:(nonnull NSString *)name;
/**
Initialize a new client with a listener endpoint sent from another process.
@param listener An NSXPCListenerEndpoint to connect to.
*/
- (nullable instancetype)initClientWithListener:(nonnull NSXPCListenerEndpoint *)listener;
/**
Call when the properties of the object have been set-up and you're ready for connections.
For clients, this call can take up to 2s to complete for connection to finish establishing though
in basically all cases it will actually complete in a few milliseconds.
*/
- (void)resume;
/**
Invalidate the connection(s). This must be done before the object can be released.
*/
- (void)invalidate;
/**
The interface the remote object should conform to. (client)
*/
@property(retain, nullable) NSXPCInterface *remoteInterface;
/**
A proxy to the object at the other end of the connection. (client)
@note If the connection to the server failed, this will be nil, so you can safely send messages
and rely on the invalidationHandler for handling the failure.
*/
@property(readonly, nonatomic, nullable) id remoteObjectProxy;
/**
The interface this object exports. (server)
*/
@property(retain, nullable) NSXPCInterface *exportedInterface;
/**
The object that responds to messages from the other end. (server)
*/
@property(retain, nullable) id exportedObject;
/**
A block to run when a/the connection is accepted and fully established.
*/
@property(copy, nullable) void (^acceptedHandler)(void);
/**
A block to run when a/the connection is invalidated/interrupted/rejected.
*/
@property(copy, nullable) void (^invalidationHandler)(void);
@end

View File

@@ -1,210 +0,0 @@
/// Copyright 2015 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
#import "SNTXPCConnection.h"
#import "MOLCodesignChecker.h"
#import "SNTStrengthify.h"
/**
Protocol used during connection establishment, @see SNTXPCConnectionInterface
*/
@protocol SNTXPCConnectionProtocol
- (void)connectWithReply:(void (^)())reply;
@end
/**
Recipient object used during connection establishment. Each incoming connection
has one of these objects created which accept the message in the protocol
and call the block provided during creation before replying.
This allows the server to reset the connection's exported interface and
object to the correct values after the client has sent the establishment message.
*/
@interface SNTXPCConnectionInterface : NSObject<SNTXPCConnectionProtocol>
@property(strong) void (^block)(void);
@end
@implementation SNTXPCConnectionInterface
- (void)connectWithReply:(void (^)())reply {
if (self.block) self.block();
reply();
}
@end
@interface SNTXPCConnection ()
@property NSXPCInterface *validationInterface;
/// The XPC listener (server only).
@property NSXPCListener *listenerObject;
/// The current connection object (client only).
@property NSXPCConnection *currentConnection;
@end
@implementation SNTXPCConnection
#pragma mark Initializers
- (instancetype)initServerWithListener:(NSXPCListener *)listener {
self = [super init];
if (self) {
_listenerObject = listener;
_validationInterface =
[NSXPCInterface interfaceWithProtocol:@protocol(SNTXPCConnectionProtocol)];
}
return self;
}
- (instancetype)initServerWithName:(NSString *)name {
return [self initServerWithListener:[[NSXPCListener alloc] initWithMachServiceName:name]];
}
- (instancetype)initClientWithListener:(NSXPCListenerEndpoint *)listener {
self = [super init];
if (self) {
_currentConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:listener];
if (!_currentConnection) return nil;
_validationInterface =
[NSXPCInterface interfaceWithProtocol:@protocol(SNTXPCConnectionProtocol)];
}
return self;
}
- (instancetype)initClientWithName:(NSString *)name privileged:(BOOL)privileged {
self = [super init];
if (self) {
NSXPCConnectionOptions options = (privileged ? NSXPCConnectionPrivileged : 0);
_currentConnection = [[NSXPCConnection alloc] initWithMachServiceName:name options:options];
if (!_currentConnection) return nil;
_validationInterface =
[NSXPCInterface interfaceWithProtocol:@protocol(SNTXPCConnectionProtocol)];
}
return self;
}
- (instancetype)initClientWithServiceName:(NSString *)name {
self = [super init];
if (self) {
_currentConnection = [[NSXPCConnection alloc] initWithServiceName:name];
if (!_currentConnection) return nil;
_validationInterface =
[NSXPCInterface interfaceWithProtocol:@protocol(SNTXPCConnectionProtocol)];
}
return self;
}
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
#pragma mark Connection set-up
- (void)resume {
if (self.listenerObject) {
self.listenerObject.delegate = self;
[self.listenerObject resume];
} else {
WEAKIFY(self);
// Set-up the connection with the remote interface set to the validation interface,
// send a message to the listener to finish establishing the connection
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
self.currentConnection.remoteObjectInterface = self.validationInterface;
self.currentConnection.interruptionHandler = self.currentConnection.invalidationHandler = ^{
STRONGIFY(self);
if (self.invalidationHandler) self.invalidationHandler();
};
[self.currentConnection resume];
[[self.currentConnection remoteObjectProxy] connectWithReply:^{
STRONGIFY(self);
// The connection is now established
[self.currentConnection suspend];
self.currentConnection.remoteObjectInterface = self.remoteInterface;
[self.currentConnection resume];
dispatch_semaphore_signal(sema);
if (self.acceptedHandler) self.acceptedHandler();
}];
if (dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC))) {
// This is unusual - as we're not inside a block - but necessary in case the caller sets an
// invalidation handler that causes this instance to be released (which is a reasonable
// approach). If establishing a connection fails, the invalidation handler will be called
// and then shortly after this bit of code will run causing a crash.
STRONGIFY(self);
// Connection was not established in a reasonable time, invalidate.
self.currentConnection.remoteObjectInterface = nil; // ensure clients don't try to use it.
[self.currentConnection invalidate];
}
}
}
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)connection {
pid_t pid = connection.processIdentifier;
MOLCodesignChecker *otherCS = [[MOLCodesignChecker alloc] initWithPID:pid];
if (![otherCS signingInformationMatches:[[MOLCodesignChecker alloc] initWithSelf]]) {
return NO;
}
// The client passed the code signature check, now we need to resume the listener and
// return YES so that the client can send the connectWithReply message. Once the client does
// we reset the connection's exportedInterface and exportedObject.
SNTXPCConnectionInterface *ci = [[SNTXPCConnectionInterface alloc] init];
WEAKIFY(self);
WEAKIFY(connection);
ci.block = ^{
STRONGIFY(self)
STRONGIFY(connection);
[connection suspend];
connection.invalidationHandler = connection.interruptionHandler = ^{
if (self.invalidationHandler) self.invalidationHandler();
};
connection.exportedInterface = self.exportedInterface;
connection.exportedObject = self.exportedObject;
[connection resume];
// The connection is now established.
if (self.acceptedHandler) self.acceptedHandler();
};
connection.exportedInterface = self.validationInterface;
connection.exportedObject = ci;
[connection resume];
return YES;
}
- (id)remoteObjectProxy {
if (self.currentConnection.remoteObjectInterface &&
self.currentConnection.remoteObjectInterface != self.validationInterface) {
return [self.currentConnection remoteObjectProxyWithErrorHandler:^(NSError *error) {
[self.currentConnection invalidate];
}];
}
return nil;
}
#pragma mark Connection tear-down
- (void)invalidate {
if (self.currentConnection) {
[self.currentConnection invalidate];
self.currentConnection = nil;
} else if (self.listenerObject) {
[self.listenerObject invalidate];
}
}
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import <MOLCertificate/MOLCertificate.h>
@@ -23,7 +23,7 @@
@class SNTRule;
@class SNTStoredEvent;
@class SNTXPCConnection;
@class MOLXPCConnection;
///
/// Protocol implemented by santad and utilized by santactl
@@ -33,9 +33,11 @@
///
/// Kernel ops
///
- (void)cacheCounts:(void (^)(uint64_t rootCache, uint64_t nonRootCache))reply;
- (void)cacheCounts:(void (^)(uint64_t count))reply;
- (void)flushCache:(void (^)(BOOL))reply;
- (void)checkCacheForVnodeID:(uint64_t)vnodeID withReply:(void (^)(santa_action_t))reply;
- (void)cacheBucketCount:(void (^)(NSArray *))reply;
- (void)checkCacheForVnodeID:(santa_vnode_id_t)vnodeID withReply:(void (^)(santa_action_t))reply;
- (void)driverConnectionEstablished:(void (^)(BOOL))reply;
///
/// Database ops
@@ -72,16 +74,19 @@
///
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply;
- (void)clientMode:(void (^)(SNTClientMode))reply;
- (void)setClientMode:(SNTClientMode)mode reply:(void (^)())reply;
- (void)setClientMode:(SNTClientMode)mode reply:(void (^)(void))reply;
- (void)xsrfToken:(void (^)(NSString *))reply;
- (void)setXsrfToken:(NSString *)token reply:(void (^)())reply;
- (void)setSyncLastSuccess:(NSDate *)date reply:(void (^)())reply;
- (void)setRuleSyncLastSuccess:(NSDate *)date reply:(void (^)())reply;
- (void)setSyncCleanRequired:(BOOL)cleanReqd reply:(void (^)())reply;
- (void)setWhitelistPathRegex:(NSString *)pattern reply:(void (^)())reply;
- (void)setBlacklistPathRegex:(NSString *)pattern reply:(void (^)())reply;
- (void)setXsrfToken:(NSString *)token reply:(void (^)(void))reply;
- (void)fullSyncLastSuccess:(void (^)(NSDate *))reply;
- (void)setFullSyncLastSuccess:(NSDate *)date reply:(void (^)(void))reply;
- (void)ruleSyncLastSuccess:(void (^)(NSDate *))reply;
- (void)setRuleSyncLastSuccess:(NSDate *)date reply:(void (^)(void))reply;
- (void)syncCleanRequired:(void (^)(BOOL))reply;
- (void)setSyncCleanRequired:(BOOL)cleanReqd reply:(void (^)(void))reply;
- (void)setWhitelistPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)setBlacklistPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)bundlesEnabled:(void (^)(BOOL))reply;
- (void)setBundlesEnabled:(BOOL)bundlesEnabled reply:(void (^)())reply;
- (void)setBundlesEnabled:(BOOL)bundlesEnabled reply:(void (^)(void))reply;
///
/// GUI Ops
@@ -94,7 +99,7 @@
///
- (void)setSyncdListener:(NSXPCListenerEndpoint *)listener;
- (void)pushNotifications:(void (^)(BOOL))reply;
- (void)postRuleSyncNotificationWithCustomMessage:(NSString *)message reply:(void (^)())reply;
- (void)postRuleSyncNotificationWithCustomMessage:(NSString *)message reply:(void (^)(void))reply;
///
/// Bundle Ops
@@ -118,9 +123,9 @@
+ (NSXPCInterface *)controlInterface;
///
/// Retrieve a pre-configured SNTXPCConnection for communicating with santad.
/// Retrieve a pre-configured MOLXPCConnection for communicating with santad.
/// Connections just needs any handlers set and then can be resumed and used.
///
+ (SNTXPCConnection *)configuredConnection;
+ (MOLXPCConnection *)configuredConnection;
@end

View File

@@ -14,9 +14,10 @@
#import "SNTXPCControlInterface.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTRule.h"
#import "SNTStoredEvent.h"
#import "SNTXPCConnection.h"
@implementation SNTXPCControlInterface
@@ -50,8 +51,8 @@
return r;
}
+ (SNTXPCConnection *)configuredConnection {
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithName:[self serviceId]
+ (MOLXPCConnection *)configuredConnection {
MOLXPCConnection *c = [[MOLXPCConnection alloc] initClientWithName:[self serviceId]
privileged:YES];
c.remoteInterface = [self controlInterface];
return c;

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"
#import "SNTXPCBundleServiceInterface.h"

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"

View File

@@ -40,9 +40,21 @@
#define OSDecrementAtomic(addr) OSAtomicDecrement64((volatile int64_t *)addr)
#endif // KERNEL
/**
A type to specialize to help SantaCache with its hashing.
The default works for numeric types with a multiplicative hash
using a prime near to the golden ratio, per Knuth.
*/
template<typename T> uint64_t SantaCacheHasher(T const& t) {
return t * 11400714819323198549UL;
};
/**
A somewhat simple, concurrent linked-list hash table intended for use in IOKit kernel extensions.
Maps 64-bit unsigned integer keys to values.
The type used for keys must overload the == operator and a specialization of
SantaCacheHasher must exist for it.
Enforces a maximum size by clearing all entries if a new value
is added that would go over the maximum size declared at creation.
@@ -50,7 +62,7 @@
The number of buckets is calculated as `maximum_size` / `per_bucket`
rounded up to the next power of 2. Locking is done per-bucket.
*/
template<class T> class SantaCache {
template<typename KeyT, typename ValueT> class SantaCache {
public:
/**
Initialize a newly created cache.
@@ -65,8 +77,7 @@ template<class T> class SantaCache {
if (unlikely(per_bucket < 1)) per_bucket = 1;
if (unlikely(per_bucket > 64)) per_bucket = 64;
max_size_ = maximum_size;
bucket_count_ = 1 << (32 - __builtin_clz(
((uint32_t)max_size_ / per_bucket) - 1));
bucket_count_ = 1 << (32 - __builtin_clz(((uint32_t)max_size_ / per_bucket) - 1));
buckets_ = (struct bucket *)IOMalloc(bucket_count_ * sizeof(struct bucket));
bzero(buckets_, bucket_count_ * sizeof(struct bucket));
}
@@ -82,13 +93,13 @@ template<class T> class SantaCache {
/**
Get an element from the cache. Returns zero_ if item doesn't exist.
*/
T get(uint64_t key) {
ValueT get(KeyT key) {
struct bucket *bucket = &buckets_[hash(key)];
lock(bucket);
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
while (entry != nullptr) {
if (entry->key == key) {
T val = entry->value;
ValueT val = entry->value;
unlock(bucket);
return val;
}
@@ -102,103 +113,39 @@ template<class T> class SantaCache {
Set an element in the cache.
@note If the cache is full when this is called, this will
empty the cache before inserting the new value.
empty the cache before inserting the new value.
@param key, The key
@param value, The value with parameterized type
@param previous_value, If the has_prev_value parameter is true the new
value will only be set if this parameter is equal to the provided value.
This allows set to become a CAS operation.
@param has_prev_value, Pass true if previous_value should be used.
@param key, The key.
@param value, The value with parameterized type.
@return the previous value (which may be zero_)
@return true if the value was set.
*/
T set(uint64_t key, T value, T previous_value, bool has_prev_value) {
struct bucket *bucket = &buckets_[hash(key)];
lock(bucket);
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
struct entry *previous_entry = nullptr;
while (entry != nullptr) {
if (entry->key == key) {
T existing_value = entry->value;
if (has_prev_value && previous_value != existing_value) {
unlock(bucket);
return existing_value;
}
entry->value = value;
if (value == zero_) {
if (previous_entry != nullptr) {
previous_entry->next = entry->next;
} else {
bucket->head = (struct entry *)((uintptr_t)entry->next + 1);
}
IOFreeAligned(entry, sizeof(struct entry));
OSDecrementAtomic(&count_);
}
unlock(bucket);
return existing_value;
}
previous_entry = entry;
entry = entry->next;
}
// If value is zero_, we're clearing but there's nothing to clear
// so we don't need to do anything else. Alternatively, if has_prev_value
// is true and is not zero_ we don't want to set a value.
if (value == zero_ || (has_prev_value && previous_value != zero_)) {
unlock(bucket);
return zero_;
}
// Check that adding this new item won't take the cache
// over its maximum size.
if (count_ + 1 > max_size_) {
unlock(bucket);
lock(&clear_bucket_);
// Check again in case clear has already run while waiting for lock
if (count_ + 1 > max_size_) {
clear();
}
lock(bucket);
unlock(&clear_bucket_);
}
// Allocate a new entry, set the key and value, then put this new entry at
// the head of this bucket's linked list.
struct entry *new_entry = (struct entry *)IOMallocAligned(
sizeof(struct entry), 2);
new_entry->key = key;
new_entry->value = value;
new_entry->next = (struct entry *)((uintptr_t)bucket->head - 1);
bucket->head = (struct entry *)((uintptr_t)new_entry + 1);
OSIncrementAtomic(&count_);
unlock(bucket);
return zero_;
}
/**
Overload to allow setting without providing a previous value
*/
T set(uint64_t key, T value) {
bool set(KeyT key, ValueT value) {
return set(key, value, {}, false);
}
/**
Overload to allow setting while providing a previous value
Set an element in the cache.
@note If the cache is full when this is called, this will
empty the cache before inserting the new value.
@param key, The key.
@param value, The value with parameterized type.
@param previous_value, the new value will only be set if this
parameter is equal to the existing value in the cache.
This allows set to become a CAS operation.
@return true if the value was set
*/
T set(uint64_t key, T value, T previous_value) {
bool set(KeyT key, ValueT value, ValueT previous_value) {
return set(key, value, previous_value, true);
}
/**
An alias for `set(key, zero_)`
*/
inline void remove(uint64_t key) {
inline void remove(KeyT key) {
set(key, zero_);
}
@@ -238,10 +185,42 @@ template<class T> class SantaCache {
return count_;
}
/**
Fill in the per_bucket_counts array with the number of entries in each bucket.
The per_buckets_count array will contain the per-bucket counts, up to the number
in array_size. The start_bucket parameter will determine which bucket to start off
with and upon return will contain either 0 if no buckets are remaining or the next
bucket to begin with when called again.
*/
void bucket_counts(uint16_t *per_bucket_counts, uint16_t *array_size, uint64_t *start_bucket) {
if (per_bucket_counts == nullptr || array_size == nullptr || start_bucket == nullptr) return;
uint64_t start = *start_bucket;
uint16_t size = *array_size;
if (start + size > bucket_count_) size = bucket_count_ - start;
for (uint16_t i = 0; i < size; ++i) {
uint16_t count = 0;
struct bucket *bucket = &buckets_[start++];
lock(bucket);
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
while (entry != nullptr) {
if (entry->value != zero_) ++count;
entry = entry->next;
}
unlock(bucket);
per_bucket_counts[i] = count;
}
*array_size = size;
*start_bucket = (start >= bucket_count_) ? 0 : start;
}
private:
struct entry {
uint64_t key;
T value;
KeyT key;
ValueT value;
struct entry *next;
};
@@ -251,6 +230,88 @@ template<class T> class SantaCache {
struct entry *head;
};
/**
Set an element in the cache.
@note If the cache is full when this is called, this will
empty the cache before inserting the new value.
@param key, The key
@param value, The value with parameterized type
@param previous_value, If has_prev_value is true, the new value will only
be set if this parameter is equal to the existing value in the cache.
This allows set to become a CAS operation.
@param has_prev_value, Pass true if previous_value should be used.
@return true if the entry was set, false if it was not
*/
bool set(KeyT key, ValueT value, ValueT previous_value, bool has_prev_value) {
struct bucket *bucket = &buckets_[hash(key)];
lock(bucket);
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
struct entry *previous_entry = nullptr;
while (entry != nullptr) {
if (entry->key == key) {
ValueT existing_value = entry->value;
if (has_prev_value && previous_value != existing_value) {
unlock(bucket);
return false;
}
entry->value = value;
if (value == zero_) {
if (previous_entry != nullptr) {
previous_entry->next = entry->next;
} else {
bucket->head = (struct entry *)((uintptr_t)entry->next + 1);
}
IOFreeAligned(entry, sizeof(struct entry));
OSDecrementAtomic(&count_);
}
unlock(bucket);
return true;
}
previous_entry = entry;
entry = entry->next;
}
// If value is zero_, we're clearing but there's nothing to clear
// so we don't need to do anything else. Alternatively, if has_prev_value
// is true and is not zero_ we don't want to set a value.
if (value == zero_ || (has_prev_value && previous_value != zero_)) {
unlock(bucket);
return false;
}
// Check that adding this new item won't take the cache
// over its maximum size.
if (count_ + 1 > max_size_) {
unlock(bucket);
lock(&clear_bucket_);
// Check again in case clear has already run while waiting for lock
if (count_ + 1 > max_size_) {
clear();
}
lock(bucket);
unlock(&clear_bucket_);
}
// Allocate a new entry, set the key and value, then put this new entry at
// the head of this bucket's linked list.
struct entry *new_entry = (struct entry *)IOMallocAligned(sizeof(struct entry), 2);
new_entry->key = key;
new_entry->value = value;
new_entry->next = (struct entry *)((uintptr_t)bucket->head - 1);
bucket->head = (struct entry *)((uintptr_t)new_entry + 1);
OSIncrementAtomic(&count_);
unlock(bucket);
return true;
}
/**
Lock a bucket. Spins until the lock is acquired.
*/
@@ -277,7 +338,7 @@ template<class T> class SantaCache {
/**
Holder for a 'zero' entry for the current type
*/
const T zero_ = {};
const ValueT zero_ = {};
/**
Special bucket used when automatically clearing due to size
@@ -288,13 +349,9 @@ template<class T> class SantaCache {
/**
Hash a key to determine which bucket it belongs in.
Multiplicative hash using a prime near to the golden ratio, per Knuth.
This seems to have good bucket distribution generally and for the range of
values we expect to see.
*/
inline uint64_t hash(uint64_t input) const {
return (input * 11400714819323198549ul) % bucket_count_;
inline uint64_t hash(KeyT input) const {
return SantaCacheHasher<KeyT>(input) % bucket_count_;
}
};

View File

@@ -19,6 +19,10 @@ OSDefineMetaClassAndStructors(SantaDecisionManager, OSObject);
#pragma mark Object Lifecycle
template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& s) {
return (SantaCacheHasher<uint64_t>(s.fsid) << 1) ^ SantaCacheHasher<uint64_t>(s.fileid);
}
bool SantaDecisionManager::init() {
if (!super::init()) return false;
@@ -29,9 +33,8 @@ bool SantaDecisionManager::init() {
decision_dataqueue_lock_ = lck_mtx_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
log_dataqueue_lock_ = lck_mtx_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
root_decision_cache_ = new SantaCache<uint64_t>(5000, 2);
non_root_decision_cache_ = new SantaCache<uint64_t>(500, 2);
vnode_pid_map_ = new SantaCache<uint64_t>(2000, 5);
decision_cache_ = new SantaCache<santa_vnode_id_t, uint64_t>(10000, 2);
vnode_pid_map_ = new SantaCache<santa_vnode_id_t, uint64_t>(2000, 5);
decision_dataqueue_ = IOSharedDataQueue::withEntries(
kMaxDecisionQueueEvents, sizeof(santa_message_t));
@@ -42,17 +45,12 @@ bool SantaDecisionManager::init() {
if (!log_dataqueue_) return kIOReturnNoMemory;
client_pid_ = 0;
root_fsid_ = 0;
ts_ = { .tv_sec = kRequestLoopSleepMilliseconds / 1000,
.tv_nsec = kRequestLoopSleepMilliseconds % 1000 * 1000000 };
return true;
}
void SantaDecisionManager::free() {
delete root_decision_cache_;
delete non_root_decision_cache_;
delete decision_cache_;
delete vnode_pid_map_;
if (decision_dataqueue_lock_) {
@@ -93,17 +91,6 @@ void SantaDecisionManager::ConnectClient(pid_t pid) {
client_pid_ = pid;
// Determine root fsid
vfs_context_t ctx = vfs_context_create(NULL);
if (ctx) {
vnode_t root = vfs_rootvnode();
if (root) {
root_fsid_ = GetVnodeIDForVnode(ctx, root) >> 32;
vnode_put(root);
}
vfs_context_rele(ctx);
}
// Any decisions made while the daemon wasn't
// connected should be cleared
ClearCache();
@@ -112,8 +99,8 @@ void SantaDecisionManager::ConnectClient(pid_t pid) {
failed_log_queue_requests_ = 0;
}
void SantaDecisionManager::DisconnectClient(bool itDied) {
if (client_pid_ < 1) return;
void SantaDecisionManager::DisconnectClient(bool itDied, pid_t pid) {
if (client_pid_ == 0 || (pid > 0 && pid != client_pid_)) return;
client_pid_ = 0;
// Ask santad to shutdown, in case it's running.
@@ -210,69 +197,58 @@ kern_return_t SantaDecisionManager::StopListener() {
#pragma mark Cache Management
/**
Return the correct cache for a given identifier.
@param identifier The identifier
@return SantaCache* The cache to use
*/
SantaCache<uint64_t>* SantaDecisionManager::CacheForIdentifier(
const uint64_t identifier) {
return (identifier >> 32 == root_fsid_) ?
root_decision_cache_ : non_root_decision_cache_;
}
void SantaDecisionManager::AddToCache(
uint64_t identifier, santa_action_t decision, uint64_t microsecs) {
// Decision is stored in upper 8 bits, timestamp in remaining 56.
uint64_t val = ((uint64_t)decision << 56) | (microsecs & 0xFFFFFFFFFFFFFF);
auto decision_cache = CacheForIdentifier(identifier);
santa_vnode_id_t identifier, santa_action_t decision, uint64_t microsecs) {
switch (decision) {
case ACTION_REQUEST_BINARY:
decision_cache->set(identifier, val, 0);
decision_cache_->set(identifier, (uint64_t)ACTION_REQUEST_BINARY << 56, 0);
break;
case ACTION_RESPOND_ACK:
decision_cache_->set(identifier, (uint64_t)ACTION_RESPOND_ACK << 56,
((uint64_t)ACTION_REQUEST_BINARY << 56));
break;
case ACTION_RESPOND_ALLOW:
case ACTION_RESPOND_DENY:
decision_cache->set(
identifier, val, ((uint64_t)ACTION_REQUEST_BINARY << 56));
case ACTION_RESPOND_DENY: {
// Decision is stored in upper 8 bits, timestamp in remaining 56.
uint64_t val = ((uint64_t)decision << 56) | (microsecs & 0xFFFFFFFFFFFFFF);
if (!decision_cache_->set(identifier, val, ((uint64_t)ACTION_REQUEST_BINARY << 56))) {
decision_cache_->set(identifier, val, ((uint64_t)ACTION_RESPOND_ACK << 56));
}
break;
}
default:
break;
}
wakeup((void *)identifier);
wakeup((void *)identifier.unsafe_simple_id());
}
void SantaDecisionManager::RemoveFromCache(uint64_t identifier) {
CacheForIdentifier(identifier)->remove(identifier);
if (unlikely(!identifier)) return;
wakeup((void *)identifier);
void SantaDecisionManager::RemoveFromCache(santa_vnode_id_t identifier) {
if (unlikely(identifier.fsid == 0 && identifier.fileid == 0)) return;
decision_cache_->remove(identifier);
wakeup((void *)identifier.unsafe_simple_id());
}
uint64_t SantaDecisionManager::RootCacheCount() const {
return root_decision_cache_->count();
uint64_t SantaDecisionManager::CacheCount() const {
return decision_cache_->count();
}
uint64_t SantaDecisionManager::NonRootCacheCount() const {
return non_root_decision_cache_->count();
void SantaDecisionManager::ClearCache() {
decision_cache_->clear();
}
void SantaDecisionManager::ClearCache(bool non_root_only) {
if (!non_root_only) root_decision_cache_->clear();
non_root_decision_cache_->clear();
void SantaDecisionManager::CacheBucketCount(
uint16_t *per_bucket_counts, uint16_t *array_size, uint64_t *start_bucket) {
decision_cache_->bucket_counts(per_bucket_counts, array_size, start_bucket);
}
#pragma mark Decision Fetching
santa_action_t SantaDecisionManager::GetFromCache(uint64_t identifier) {
santa_action_t SantaDecisionManager::GetFromCache(santa_vnode_id_t identifier) {
auto result = ACTION_UNSET;
uint64_t decision_time = 0;
auto decision_cache = CacheForIdentifier(identifier);
uint64_t cache_val = decision_cache->get(identifier);
uint64_t cache_val = decision_cache_->get(identifier);
if (cache_val == 0) return result;
// Decision is stored in upper 8 bits, timestamp in remaining 56.
@@ -283,7 +259,7 @@ santa_action_t SantaDecisionManager::GetFromCache(uint64_t identifier) {
if (result == ACTION_RESPOND_DENY) {
auto expiry_time = decision_time + (kMaxDenyCacheTimeMilliseconds * 1000);
if (expiry_time < GetCurrentUptime()) {
decision_cache->remove(identifier);
decision_cache_->remove(identifier);
return ACTION_UNSET;
}
}
@@ -293,7 +269,7 @@ santa_action_t SantaDecisionManager::GetFromCache(uint64_t identifier) {
}
santa_action_t SantaDecisionManager::GetFromDaemon(
santa_message_t *message, uint64_t identifier) {
santa_message_t *message, santa_vnode_id_t identifier) {
auto return_action = ACTION_UNSET;
#ifdef DEBUG
@@ -316,10 +292,16 @@ santa_action_t SantaDecisionManager::GetFromDaemon(
return ACTION_ERROR;
}
// Check the cache every kRequestLoopSleepMilliseconds. Break this loop and send the request
// again if kRequestCacheChecks is reached. Don't break the loop if the daemon is working on the
// request, indicated with ACTION_RESPOND_ACK.
auto cache_check_count = 0;
do {
msleep((void *)message->vnode_id, NULL, 0, "", &ts_);
msleep((void *)message->vnode_id.unsafe_simple_id(), NULL, 0, "", &ts_);
return_action = GetFromCache(identifier);
} while (return_action == ACTION_REQUEST_BINARY && ClientConnected());
} while (ClientConnected() &&
((return_action == ACTION_REQUEST_BINARY && ++cache_check_count < kRequestCacheChecks)
|| (return_action == ACTION_RESPOND_ACK)));
} while (!RESPONSE_VALID(return_action) && ClientConnected());
// If response is still not valid, the daemon exited
@@ -342,7 +324,7 @@ santa_action_t SantaDecisionManager::GetFromDaemon(
santa_action_t SantaDecisionManager::FetchDecision(
const kauth_cred_t cred,
const vnode_t vp,
const uint64_t vnode_id) {
const santa_vnode_id_t vnode_id) {
while (true) {
if (!ClientConnected()) return ACTION_RESPOND_ALLOW;
@@ -354,10 +336,10 @@ santa_action_t SantaDecisionManager::FetchDecision(
// If item is not in cache, break out of loop to send request to daemon.
if (RESPONSE_VALID(return_action)) {
return return_action;
} else if (return_action == ACTION_REQUEST_BINARY) {
} else if (return_action == ACTION_REQUEST_BINARY || return_action == ACTION_RESPOND_ACK) {
// This thread will now sleep for kRequestLoopSleepMilliseconds (1s) or
// until AddToCache is called, indicating a response has arrived.
msleep((void *)vnode_id, NULL, 0, "", &ts_);
msleep((void *)vnode_id.unsafe_simple_id(), NULL, 0, "", &ts_);
} else {
break;
}
@@ -392,7 +374,6 @@ bool SantaDecisionManager::PostToDecisionQueue(santa_message_t *message) {
LOGE("Failed to queue more than %d decision requests, killing daemon",
kMaxDecisionQueueFailures);
proc_signal(client_pid_, SIGKILL);
client_pid_ = 0;
}
}
lck_mtx_unlock(decision_dataqueue_lock_);
@@ -406,10 +387,6 @@ bool SantaDecisionManager::PostToLogQueue(santa_message_t *message) {
if (failed_log_queue_requests_++ == 0) {
LOGW("Dropping log queue messages");
}
// If enqueue failed, pop an item off the queue and try again.
uint32_t dataSize = 0;
log_dataqueue_->dequeue(0, &dataSize);
kr = log_dataqueue_->enqueue(message, sizeof(santa_message_t));
} else {
if (failed_log_queue_requests_ > 0) {
failed_log_queue_requests_--;
@@ -437,19 +414,11 @@ int SantaDecisionManager::VnodeCallback(const kauth_cred_t cred,
int *errno) {
// Get ID for the vnode
auto vnode_id = GetVnodeIDForVnode(ctx, vp);
if (!vnode_id) return KAUTH_RESULT_DEFER;
if (vnode_id.fsid == 0 && vnode_id.fileid == 0) return KAUTH_RESULT_DEFER;
// Fetch decision
auto returnedAction = FetchDecision(cred, vp, vnode_id);
// 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)) {
RemoveFromCache(vnode_id);
returnedAction = ACTION_RESPOND_DENY;
}
switch (returnedAction) {
case ACTION_RESPOND_ALLOW: {
auto proc = vfs_context_proc(ctx);
@@ -486,9 +455,7 @@ void SantaDecisionManager::FileOpCallback(
auto vnode_id = GetVnodeIDForVnode(context, vp);
vfs_context_rele(context);
if (action == KAUTH_FILEOP_CLOSE) {
RemoveFromCache(vnode_id);
} else if (action == KAUTH_FILEOP_EXEC) {
if (action == KAUTH_FILEOP_EXEC) {
auto message = NewMessage(nullptr);
message->vnode_id = vnode_id;
message->action = ACTION_NOTIFY_EXEC;
@@ -604,8 +571,12 @@ extern "C" int vnode_scope_callback(
reinterpret_cast<int *>(arg3));
sdm->DecrementListenerInvocations();
return result;
} else if (action & KAUTH_VNODE_WRITE_DATA) {
} else if (action & KAUTH_VNODE_WRITE_DATA || action & KAUTH_VNODE_APPEND_DATA) {
sdm->IncrementListenerInvocations();
if (!(action & KAUTH_VNODE_ACCESS)) {
auto vnode_id = sdm->GetVnodeIDForVnode(reinterpret_cast<vfs_context_t>(arg0), vp);
sdm->RemoveFromCache(vnode_id);
}
char path[MAXPATHLEN];
int pathlen = MAXPATHLEN;
vn_getpath(vp, path, &pathlen);

View File

@@ -64,7 +64,7 @@ class SantaDecisionManager : public OSObject {
void ConnectClient(pid_t pid);
/// Called by SantaDriverClient when a client disconnects
void DisconnectClient(bool itDied = false);
void DisconnectClient(bool itDied = false, pid_t pid = proc_selfpid());
/// Returns whether a client is currently connected or not.
bool ClientConnected() const;
@@ -86,7 +86,7 @@ class SantaDecisionManager : public OSObject {
kern_return_t StopListener();
/// Adds a decision to the cache, with a timestamp.
void AddToCache(uint64_t identifier,
void AddToCache(santa_vnode_id_t identifier,
const santa_action_t decision,
const uint64_t microsecs = GetCurrentUptime());
@@ -94,20 +94,30 @@ class SantaDecisionManager : public OSObject {
Fetches a response from the cache, first checking to see if the entry
has expired.
*/
santa_action_t GetFromCache(uint64_t identifier);
santa_action_t GetFromCache(santa_vnode_id_t identifier);
/// Checks to see if a given identifier is in the cache and removes it.
void RemoveFromCache(uint64_t identifier);
void RemoveFromCache(santa_vnode_id_t identifier);
/// Returns the number of entries in the cache.
uint64_t RootCacheCount() const;
uint64_t NonRootCacheCount() const;
uint64_t CacheCount() const;
/// Clears the cache.
void ClearCache();
/**
Clears the cache(s). If non_root_only is true, only the non-root cache
is cleared.
Fills out the per_bucket_counts array with the number of items in each bucket in the
non-root decision cache.
@param per_bucket_counts An array of uint16_t's to fill in with the number of items in each
bucket. The size of this array is expected to equal array_size.
@param array_size The size of the per_bucket_counts array on input. Upon return this will be
updated to the number of slots that were actually used.
@param start_bucket If non-zero this is the bucket in the cache to start from. Upon return this
will be the next numbered bucket to start from for subsequent requests.
*/
void ClearCache(bool non_root_only = false);
void CacheBucketCount(uint16_t *per_bucket_counts, uint16_t *array_size, uint64_t *start_bucket);
/// Increments the count of active callbacks pending.
void IncrementListenerInvocations();
@@ -115,6 +125,25 @@ class SantaDecisionManager : public OSObject {
/// Decrements the count of active callbacks pending.
void DecrementListenerInvocations();
/**
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 santa_vnode_id_t The Vnode ID.
*/
static inline santa_vnode_id_t GetVnodeIDForVnode(const vfs_context_t ctx, const vnode_t vp) {
struct vnode_attr vap;
VATTR_INIT(&vap);
VATTR_WANTED(&vap, va_fsid);
VATTR_WANTED(&vap, va_fileid);
vnode_getattr(vp, &vap, ctx);
return {
.fsid = vap.va_fsid,
.fileid = vap.va_fileid
};
}
/**
Vnode Callback
@@ -144,6 +173,12 @@ class SantaDecisionManager : public OSObject {
*/
static const uint32_t kRequestLoopSleepMilliseconds = 1000;
/**
While waiting for a response from the daemon, this is the maximum number cache checks before
re-sending the request.
*/
static const uint32_t kRequestCacheChecks = 5;
/**
The maximum number of milliseconds a cached deny message should be
considered valid.
@@ -176,7 +211,7 @@ class SantaDecisionManager : public OSObject {
@param identifier The vnode ID string for this request
@return santa_action_t The response for this request
*/
santa_action_t GetFromDaemon(santa_message_t *message, uint64_t identifier);
santa_action_t GetFromDaemon(santa_message_t *message, santa_vnode_id_t identifier);
/**
Fetches an execution decision for a file, first using the cache and then
@@ -190,7 +225,7 @@ class SantaDecisionManager : public OSObject {
@return santa_action_t The response for this request
*/
santa_action_t FetchDecision(
const kauth_cred_t cred, const vnode_t vp, const uint64_t vnode_id);
const kauth_cred_t cred, const vnode_t vp, const santa_vnode_id_t vnode_id);
/**
Posts the requested message to the decision data queue.
@@ -208,23 +243,6 @@ class SantaDecisionManager : public OSObject {
*/
bool PostToLogQueue(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.
*/
static inline uint64_t GetVnodeIDForVnode(
const vfs_context_t ctx, const vnode_t vp) {
struct vnode_attr vap;
VATTR_INIT(&vap);
VATTR_WANTED(&vap, va_fsid);
VATTR_WANTED(&vap, va_fileid);
vnode_getattr(vp, &vap, ctx);
return (((uint64_t)vap.va_fsid << 32) | vap.va_fileid);
}
/**
Creates a new santa_message_t with some fields pre-filled.
@@ -261,21 +279,8 @@ class SantaDecisionManager : public OSObject {
return (uint64_t)((sec * 1000000) + usec);
}
SantaCache<uint64_t> *root_decision_cache_;
SantaCache<uint64_t> *non_root_decision_cache_;
SantaCache<uint64_t> *vnode_pid_map_;
/**
Return the correct cache for a given identifier.
@param identifier The identifier
@return SantaCache* The cache to use
*/
SantaCache<uint64_t>* CacheForIdentifier(const uint64_t identifier);
// This is the file system ID of the root filesystem,
// used to determine which cache to use for requests
uint32_t root_fsid_;
SantaCache<santa_vnode_id_t, uint64_t> *decision_cache_;
SantaCache<santa_vnode_id_t, uint64_t> *vnode_pid_map_;
lck_grp_t *sdm_lock_grp_;
lck_grp_attr_t *sdm_lock_grp_attr_;
@@ -296,7 +301,8 @@ class SantaDecisionManager : public OSObject {
kauth_listener_t vnode_listener_;
kauth_listener_t fileop_listener_;
struct timespec ts_;
struct timespec ts_= { .tv_sec = kRequestLoopSleepMilliseconds / 1000,
.tv_nsec = kRequestLoopSleepMilliseconds % 1000 * 1000000 };
};
/**

View File

@@ -37,34 +37,38 @@ bool SantaDriverClient::initWithTask(
bool SantaDriverClient::start(IOService *provider) {
myProvider = OSDynamicCast(com_google_SantaDriver, provider);
if (!myProvider) return false;
if (!super::start(provider)) return false;
decisionManager = myProvider->GetDecisionManager();
if (!decisionManager) return false;
decisionManager->retain();
return true;
return super::start(provider);
}
void SantaDriverClient::stop(IOService *provider) {
super::stop(provider);
myProvider = nullptr;
decisionManager->release();
decisionManager = nullptr;
super::stop(provider);
}
IOReturn SantaDriverClient::clientDied() {
LOGI("Client died.");
decisionManager->DisconnectClient(true);
return terminate(0) ? kIOReturnSuccess : kIOReturnError;
}
IOReturn SantaDriverClient::clientClose() {
decisionManager->DisconnectClient(true);
return terminate(kIOServiceSynchronous) ? kIOReturnSuccess : kIOReturnError;
LOGI("Client disconnected.");
decisionManager->DisconnectClient();
return terminate(0) ? kIOReturnSuccess : kIOReturnError;
}
bool SantaDriverClient::terminate(IOOptionBits options) {
decisionManager->DisconnectClient();
LOGI("Client disconnected.");
bool SantaDriverClient::didTerminate(IOService *provider, IOOptionBits options, bool *defer) {
decisionManager->DisconnectClient(false, 0);
if (myProvider && myProvider->isOpen(this)) myProvider->close(this);
return super::terminate(options);
return super::didTerminate(provider, options, defer);
}
#pragma mark Fetching memory and data queue notifications
@@ -133,9 +137,10 @@ IOReturn SantaDriverClient::allow_binary(
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
const uint64_t vnode_id = static_cast<const uint64_t>(arguments->scalarInput[0]);
if (!vnode_id) return kIOReturnInvalid;
me->decisionManager->AddToCache(vnode_id, ACTION_RESPOND_ALLOW);
if (arguments->structureInputSize != sizeof(santa_vnode_id_t)) return kIOReturnInvalid;
santa_vnode_id_t *vnode_id = (santa_vnode_id_t *)arguments->structureInput;
if (vnode_id->fsid == 0 || vnode_id->fileid == 0) return kIOReturnInvalid;
me->decisionManager->AddToCache(*vnode_id, ACTION_RESPOND_ALLOW);
return kIOReturnSuccess;
}
@@ -145,9 +150,23 @@ IOReturn SantaDriverClient::deny_binary(
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
const uint64_t vnode_id = static_cast<const uint64_t>(arguments->scalarInput[0]);
if (!vnode_id) return kIOReturnInvalid;
me->decisionManager->AddToCache(vnode_id, ACTION_RESPOND_DENY);
if (arguments->structureInputSize != sizeof(santa_vnode_id_t)) return kIOReturnInvalid;
santa_vnode_id_t *vnode_id = (santa_vnode_id_t *)arguments->structureInput;
if (vnode_id->fsid == 0 || vnode_id->fileid == 0) return kIOReturnInvalid;
me->decisionManager->AddToCache(*vnode_id, ACTION_RESPOND_DENY);
return kIOReturnSuccess;
}
IOReturn SantaDriverClient::acknowledge_binary(
OSObject *target, void *reference, IOExternalMethodArguments *arguments) {
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
if (arguments->structureInputSize != sizeof(santa_vnode_id_t)) return kIOReturnInvalid;
santa_vnode_id_t *vnode_id = (santa_vnode_id_t *)arguments->structureInput;
if (vnode_id->fsid == 0 || vnode_id->fileid == 0) return kIOReturnInvalid;
me->decisionManager->AddToCache(*vnode_id, ACTION_RESPOND_ACK);
return kIOReturnSuccess;
}
@@ -157,8 +176,7 @@ IOReturn SantaDriverClient::clear_cache(
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
const bool non_root_only = static_cast<const bool>(arguments->scalarInput[0]);
me->decisionManager->ClearCache(non_root_only);
me->decisionManager->ClearCache();
return kIOReturnSuccess;
}
@@ -168,8 +186,7 @@ IOReturn SantaDriverClient::cache_count(
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
arguments->scalarOutput[0] = me->decisionManager->RootCacheCount();
arguments->scalarOutput[1] = me->decisionManager->NonRootCacheCount();
arguments->scalarOutput[0] = me->decisionManager->CacheCount();
return kIOReturnSuccess;
}
@@ -178,8 +195,27 @@ IOReturn SantaDriverClient::check_cache(
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
const uint64_t input = static_cast<const uint64_t>(arguments->scalarInput[0]);
arguments->scalarOutput[0] = me->decisionManager->GetFromCache(input);
if (arguments->structureInputSize != sizeof(santa_vnode_id_t)) return kIOReturnInvalid;
santa_vnode_id_t *vnode_id = (santa_vnode_id_t *)arguments->structureInput;
if (vnode_id->fsid == 0 || vnode_id->fileid == 0) return kIOReturnInvalid;
arguments->scalarOutput[0] = me->decisionManager->GetFromCache(*vnode_id);
return kIOReturnSuccess;
}
IOReturn SantaDriverClient::cache_bucket_count(
OSObject *target, void *reference, IOExternalMethodArguments *arguments) {
SantaDriverClient *me = OSDynamicCast(SantaDriverClient, target);
if (!me) return kIOReturnBadArgument;
santa_bucket_count_t *counts = reinterpret_cast<santa_bucket_count_t *>(
arguments->structureOutput);
const santa_bucket_count_t *input = reinterpret_cast<const santa_bucket_count_t *>(
arguments->structureInput);
uint16_t s = sizeof(counts->per_bucket) / sizeof(uint16_t);
counts->start = input->start;
me->decisionManager->CacheBucketCount(counts->per_bucket, &s, &(counts->start));
return kIOReturnSuccess;
}
@@ -197,11 +233,14 @@ IOReturn SantaDriverClient::externalMethod(
static IOExternalMethodDispatch sMethods[kSantaUserClientNMethods] = {
// Function ptr, input scalar count, input struct size, output scalar count, output struct size
{ &SantaDriverClient::open, 0, 0, 0, 0 },
{ &SantaDriverClient::allow_binary, 1, 0, 0, 0 },
{ &SantaDriverClient::deny_binary, 1, 0, 0, 0 },
{ &SantaDriverClient::clear_cache, 1, 0, 0, 0 },
{ &SantaDriverClient::cache_count, 0, 0, 2, 0 },
{ &SantaDriverClient::check_cache, 1, 0, 1, 0 }
{ &SantaDriverClient::allow_binary, 0, sizeof(santa_vnode_id_t), 0, 0 },
{ &SantaDriverClient::deny_binary, 0, sizeof(santa_vnode_id_t), 0, 0 },
{ &SantaDriverClient::acknowledge_binary, 0, sizeof(santa_vnode_id_t), 0, 0 },
{ &SantaDriverClient::clear_cache, 0, 0, 0, 0 },
{ &SantaDriverClient::cache_count, 0, 0, 1, 0 },
{ &SantaDriverClient::check_cache, 0, sizeof(santa_vnode_id_t), 1, 0 },
{ &SantaDriverClient::cache_bucket_count, 0, sizeof(santa_bucket_count_t),
0, sizeof(santa_bucket_count_t) },
};
if (selector > static_cast<UInt32>(kSantaUserClientNMethods)) {

View File

@@ -47,11 +47,14 @@ class com_google_SantaDriverClient : public IOUserClient {
/// Called when this class is stopping
void stop(IOService *provider) override;
/// Called when a client disconnects
/// Called when a client manually disconnects (via IOServiceClose)
IOReturn clientClose() override;
/// Called when the driver is shutting down
bool terminate(IOOptionBits options) override;
/// Called when a client dies
IOReturn clientDied() override;
/// Called during termination
bool didTerminate(IOService* provider, IOOptionBits options, bool* defer) override;
/// Called in clients with IOConnectSetNotificationPort
IOReturn registerNotificationPort(
@@ -87,6 +90,11 @@ class com_google_SantaDriverClient : public IOUserClient {
static IOReturn deny_binary(
OSObject *target, void *reference, IOExternalMethodArguments *arguments);
/// The daemon calls this to acknowledge a binary request. This is used for large binaries that
/// may take a while to reach a decision.
static IOReturn acknowledge_binary(
OSObject *target, void *reference, IOExternalMethodArguments *arguments);
/// The daemon calls this to empty the cache.
static IOReturn clear_cache(
OSObject *target, void *reference, IOExternalMethodArguments *arguments);
@@ -100,6 +108,11 @@ class com_google_SantaDriverClient : public IOUserClient {
static IOReturn check_cache(
OSObject *target, void *reference, IOExternalMethodArguments *arguments);
/// The daemon calls this to find out how many items are in each cache bucket.
/// Input and output are both an instance of santa_bucket_count_t.
static IOReturn cache_bucket_count(
OSObject *target, void *reference, IOExternalMethodArguments *arguments);
private:
com_google_SantaDriver *myProvider;
SantaDecisionManager *decisionManager;

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTXPCBundleServiceInterface.h"

View File

@@ -17,16 +17,16 @@
#import <CommonCrypto/CommonDigest.h>
#import <pthread/pthread.h>
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTFileInfo.h"
#import "SNTStoredEvent.h"
#import "SNTXPCConnection.h"
#import "SNTXPCNotifierInterface.h"
@interface SNTBundleService ()
@property SNTXPCConnection *notifierConnection;
@property SNTXPCConnection *listener;
@property MOLXPCConnection *notifierConnection;
@property MOLXPCConnection *listener;
@property(nonatomic) dispatch_queue_t queue;
@end
@@ -48,7 +48,7 @@
// Create listener for return connection from SantaGUI.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.listener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.listener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.listener.exportedInterface = [SNTXPCBundleServiceInterface bundleServiceInterface];
self.listener.exportedObject = self;
self.listener.acceptedHandler = ^{
@@ -72,18 +72,18 @@
}
- (void)attemptReconnection {
[self performSelectorInBackground:@selector(createConnection) withObject:nil];
[self performSelectorOnMainThread:@selector(createConnection) withObject:nil waitUntilDone:NO];
}
#pragma mark SNTBundleServiceXPC Methods
// Connect to the SantaGUI
- (void)setBundleNotificationListener:(NSXPCListenerEndpoint *)listener {
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
[c resume];
self.notifierConnection = c;
dispatch_async(self.queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
MOLXPCConnection *c = [[MOLXPCConnection alloc] initClientWithListener:listener];
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
[c resume];
self.notifierConnection = c;
[self createConnection];
});
}
@@ -98,11 +98,20 @@
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async(self.queue, ^{
// Use the highest bundle we can find. Save and reuse the bundle infomation when creating
// the related binary events.
// Use the highest bundle we can find.
SNTFileInfo *b = [[SNTFileInfo alloc] initWithPath:event.fileBundlePath];
b.useAncestorBundle = YES;
event.fileBundlePath = b.bundlePath;
// If path to the bundle is unavailable, stop. SantaGUI will revert to
// using the offending blockable.
if (!event.fileBundlePath) {
reply(nil, nil, 0);
dispatch_semaphore_signal(sema);
return;
}
// Reuse the bundle infomation when creating the related binary events.
event.fileBundleID = b.bundleIdentifier;
event.fileBundleName = b.bundleName;
event.fileBundleVersion = b.bundleVersion;

View File

@@ -12,15 +12,16 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTBundleService.h"
#import "SNTXPCBundleServiceInterface.h"
#import "SNTXPCConnection.h"
int main(int argc, const char *argv[]) {
SNTXPCConnection *c =
[[SNTXPCConnection alloc] initServerWithListener:[NSXPCListener serviceListener]];
MOLXPCConnection *c =
[[MOLXPCConnection alloc] initServerWithListener:[NSXPCListener serviceListener]];
c.exportedInterface = [SNTXPCBundleServiceInterface bundleServiceInterface];
c.exportedObject = [[SNTBundleService alloc] init];
[c resume];

View File

@@ -15,20 +15,21 @@
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTFileInfo.h"
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
#ifdef DEBUG
@interface SNTCommandBundleInfo : SNTCommand<SNTCommandProtocol>
@end
@implementation SNTCommandBundleInfo
#ifdef DEBUG
REGISTER_COMMAND_NAME(@"bundleinfo")
#endif
+ (BOOL)requiresRoot {
return NO;
@@ -77,3 +78,5 @@ REGISTER_COMMAND_NAME(@"bundleinfo")
}
@end
#endif

View File

@@ -0,0 +1,81 @@
/// Copyright 2018 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.
#ifdef DEBUG
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTLogging.h"
#import "SNTXPCControlInterface.h"
@interface SNTCommandCacheHistogram : SNTCommand<SNTCommandProtocol>
@end
@implementation SNTCommandCacheHistogram
REGISTER_COMMAND_NAME(@"cachehistogram")
+ (BOOL)requiresRoot {
return YES;
}
+ (BOOL)requiresDaemonConn {
return YES;
}
+ (NSString *)shortHelpText {
return @"Print a cache distribution histogram.";
}
+ (NSString *)longHelpText {
return (@"Prints a histogram of each bucket of the in-kernel cache\n"
@" Use -g to get 'graphical' output\n"
@"Only available in DEBUG builds.");
}
- (void)runWithArguments:(NSArray *)arguments {
[[self.daemonConn remoteObjectProxy] cacheBucketCount:^(NSArray *counts) {
NSMutableDictionary<NSNumber *, NSNumber *> *d = [NSMutableDictionary dictionary];
[counts enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
d[obj] = @([d[obj] intValue] + 1);
}];
printf("There are %llu empty buckets\n", [d[@0] unsignedLongLongValue]);
for (NSNumber *key in [d.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
if ([key isEqual:@0]) continue;
uint64_t k = [key unsignedLongLongValue];
uint64_t v = [d[key] unsignedLongLongValue];
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"-g"]) {
printf("%4llu: ", k);
for (uint64_t y = 0; y < v; ++y) {
printf("#");
}
printf("\n");
} else {
printf("%4llu: %llu\n", k, v);
}
}
exit(0);
}];
}
@end
#endif

View File

@@ -12,25 +12,26 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTLogging.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
#include <sys/stat.h>
#ifdef DEBUG
@interface SNTCommandCheckCache : SNTCommand<SNTCommandProtocol>
@end
@implementation SNTCommandCheckCache
#ifdef DEBUG
REGISTER_COMMAND_NAME(@"checkcache")
#endif
+ (BOOL)requiresRoot {
return NO;
@@ -50,7 +51,7 @@ REGISTER_COMMAND_NAME(@"checkcache")
}
- (void)runWithArguments:(NSArray *)arguments {
uint64_t vnodeID = [self vnodeIDForFile:arguments.firstObject];
santa_vnode_id_t vnodeID = [self vnodeIDForFile:arguments.firstObject];
[[self.daemonConn remoteObjectProxy] checkCacheForVnodeID:vnodeID
withReply:^(santa_action_t action) {
if (action == ACTION_RESPOND_ALLOW) {
@@ -66,10 +67,13 @@ REGISTER_COMMAND_NAME(@"checkcache")
}];
}
- (uint64_t)vnodeIDForFile:(NSString *)path {
- (santa_vnode_id_t)vnodeIDForFile:(NSString *)path {
struct stat fstat = {};
stat(path.fileSystemRepresentation, &fstat);
return (((uint64_t)fstat.st_dev << 32) | fstat.st_ino);
santa_vnode_id_t ret = {.fsid = fstat.st_dev, .fileid = fstat.st_ino};
return ret;
}
@end
#endif

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
@@ -20,12 +20,12 @@
#import <objc/runtime.h>
#import <MOLCertificate/MOLCertificate.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCachedDecision.h"
#import "SNTFileInfo.h"
#import "SNTLogging.h"
#import "SNTRule.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
// file info keys
@@ -42,6 +42,7 @@ static NSString *const kPageZero = @"Page Zero";
static NSString *const kCodeSigned = @"Code-signed";
static NSString *const kRule = @"Rule";
static NSString *const kSigningChain = @"Signing Chain";
static NSString *const kUniversalSigningChain = @"Universal Signing Chain";
// signing chain keys
static NSString *const kCommonName = @"Common Name";
@@ -115,6 +116,7 @@ typedef id (^SNTAttributeBlock)(SNTCommandFileInfo *, SNTFileInfo *);
@property(readonly, copy, nonatomic) SNTAttributeBlock codeSigned;
@property(readonly, copy, nonatomic) SNTAttributeBlock rule;
@property(readonly, copy, nonatomic) SNTAttributeBlock signingChain;
@property(readonly, copy, nonatomic) SNTAttributeBlock universalSigningChain;
// Mapping between property string keys and SNTAttributeBlocks
@property(nonatomic) NSDictionary<NSString *, SNTAttributeBlock> *propertyMap;
@@ -182,7 +184,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
+ (NSArray<NSString *> *)fileInfoKeys {
return @[ kPath, kSHA256, kSHA1, kBundleName, kBundleVersion, kBundleVersionStr,
kDownloadReferrerURL, kDownloadURL, kDownloadTimestamp, kDownloadAgent,
kType, kPageZero, kCodeSigned, kRule, kSigningChain ];
kType, kPageZero, kCodeSigned, kRule, kSigningChain, kUniversalSigningChain ];
}
+ (NSArray<NSString *> *)signingChainKeys {
@@ -190,7 +192,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
kValidUntil ];
}
- (instancetype)initWithDaemonConnection:(SNTXPCConnection *)daemonConn {
- (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn {
self = [super initWithDaemonConnection:daemonConn];
if (self) {
_dateFormatter = [[NSDateFormatter alloc] init];
@@ -210,7 +212,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
kPageZero : self.pageZero,
kCodeSigned : self.codeSigned,
kRule : self.rule,
kSigningChain : self.signingChain };
kSigningChain : self.signingChain,
kUniversalSigningChain : self.universalSigningChain };
_printQueue = dispatch_queue_create("com.google.santactl.print_queue", DISPATCH_QUEUE_SERIAL);
}
@@ -325,6 +328,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
return @"Yes, but failed requirement validation";
case errSecCSInfoPlistFailed:
return @"Yes, but can't validate as Info.plist is missing";
case errSecCSSignatureInvalid:
if ([error.domain isEqualToString:@"com.google.molcodesignchecker"]) {
return @"Yes, but signing is not consistent for all architectures";
}
default: {
return [NSString stringWithFormat:@"Yes, but failed to validate (%ld)", error.code];
}
@@ -345,10 +352,11 @@ REGISTER_COMMAND_NAME(@"fileinfo")
dispatch_once(&token, ^{ [cmd.daemonConn resume]; });
__block SNTEventState state;
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
NSError *err;
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:&err];
[[cmd.daemonConn remoteObjectProxy] decisionForFilePath:fileInfo.path
fileSHA256:fileInfo.SHA256
certificateSHA256:csc.leafCertificate.SHA256
certificateSHA256:err ? nil : csc.leafCertificate.SHA256
reply:^(SNTEventState s) {
state = s;
dispatch_semaphore_signal(sema);
@@ -417,6 +425,46 @@ REGISTER_COMMAND_NAME(@"fileinfo")
};
}
- (SNTAttributeBlock)universalSigningChain {
return ^id (SNTCommandFileInfo *cmd, SNTFileInfo *fileInfo) {
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
if (csc.certificates.count) return nil;
if (!csc.universalSigningInformation) return nil;
NSMutableArray *universal = [NSMutableArray array];
for (NSDictionary *arch in csc.universalSigningInformation) {
[universal addObject:@{ @"arch" : arch.allKeys.firstObject }];
int flags = [arch.allValues.firstObject[(__bridge id)kSecCodeInfoFlags] intValue];
if (flags & kSecCodeSignatureAdhoc) {
[universal addObject:@{ @"ad-hoc" : @YES }];
continue;
}
NSArray *certs = arch.allValues.firstObject[(__bridge id)kSecCodeInfoCertificates];
NSArray *chain = [MOLCertificate certificatesFromArray:certs];
if (!chain.count) {
[universal addObject:@{ @"unsigned" : @YES }];
continue;
}
for (MOLCertificate *c in chain) {
[universal addObject:@{
kSHA256 : c.SHA256 ?: @"null",
kSHA1 : c.SHA1 ?: @"null",
kCommonName : c.commonName ?: @"null",
kOrganization : c.orgName ?: @"null",
kOrganizationalUnit : c.orgUnit ?: @"null",
kValidFrom : [cmd.dateFormatter stringFromDate:c.validFrom] ?: @"null",
kValidUntil : [cmd.dateFormatter stringFromDate:c.validUntil] ?: @"null"
}];
}
}
NSMutableSet *set = [NSMutableSet set];
for (NSDictionary *cert in universal) {
if (cert[@"arch"]) continue;
[set addObject:cert];
}
return (set.count > 1) ? universal : nil;
};
}
# pragma mark -
// Entry point for the command.
@@ -590,8 +638,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
} else {
for (NSString *key in self.outputKeyList) {
if (![outputDict objectForKey:key]) continue;
if ([key isEqual:kSigningChain]) {
[output appendString:[self stringForSigningChain:outputDict[key]]];
if ([key isEqual:kSigningChain] || [key isEqual:kUniversalSigningChain]) {
[output appendString:[self stringForSigningChain:outputDict[key] key:key]];
} else {
if (singleKey) {
[output appendFormat:@"%@\n", outputDict[key]];
@@ -728,14 +776,25 @@ REGISTER_COMMAND_NAME(@"fileinfo")
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
- (NSString *)stringForSigningChain:(NSArray *)signingChain {
- (NSString *)stringForSigningChain:(NSArray *)signingChain key:(NSString *)key {
if (!signingChain) return @"";
NSMutableString *result = [NSMutableString string];
[result appendFormat:@"%@:\n", kSigningChain];
[result appendFormat:@"%@:\n", key];
int i = 1;
NSArray<NSString *> *certKeys = [[self class] signingChainKeys];
for (NSDictionary *cert in signingChain) {
if ([cert isEqual:[NSNull null]]) continue;
if (cert[@"arch"]) {
[result appendFormat:@" %2@\n", [@"Architecture: " stringByAppendingString:cert[@"arch"]]];
i = 1;
continue;
} else if (cert[@"ad-hoc"]) {
[result appendFormat:@" %2d. %-20@\n", i, @"ad-hoc"];
continue;
} else if (cert[@"unsigned"]) {
[result appendFormat:@" %2d. %-20@\n", i, @"unsigned"];
continue;
}
if (i > 1) [result appendFormat:@"\n"];
[result appendString:[self stringForCertificate:cert withKeys:certKeys index:i]];
i += 1;
@@ -749,10 +808,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
BOOL firstKey = YES;
for (NSString *key in keys) {
if (firstKey) {
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
firstKey = NO;
} else {
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
}
}
return result.copy;

View File

@@ -12,13 +12,16 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#ifdef DEBUG
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTLogging.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTCommandFlushCache : SNTCommand<SNTCommandProtocol>
@@ -26,9 +29,7 @@
@implementation SNTCommandFlushCache
#ifdef DEBUG
REGISTER_COMMAND_NAME(@"flushcache")
#endif
+ (BOOL)requiresRoot {
return YES;
@@ -60,3 +61,5 @@ REGISTER_COMMAND_NAME(@"flushcache")
}
@end
#endif

View File

@@ -12,19 +12,20 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import <MOLCertificate/MOLCertificate.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTConfigurator.h"
#import "SNTDropRootPrivs.h"
#import "SNTFileInfo.h"
#include "SNTLogging.h"
#import "SNTRule.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTCommandRule : SNTCommand<SNTCommandProtocol>
@@ -163,7 +164,7 @@ REGISTER_COMMAND_NAME(@"rule")
}];
}
- (void)printStateOfRule:(SNTRule *)rule daemonConnection:(SNTXPCConnection *)daemonConn {
- (void)printStateOfRule:(SNTRule *)rule daemonConnection:(MOLXPCConnection *)daemonConn {
NSString *fileSHA256 = (rule.type == SNTRuleTypeBinary) ? rule.shasum : nil;
NSString *certificateSHA256 = (rule.type == SNTRuleTypeCertificate) ? rule.shasum : nil;
dispatch_group_t group = dispatch_group_create();

View File

@@ -12,13 +12,14 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTConfigurator.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTCommandStatus : SNTCommand<SNTCommandProtocol>
@@ -49,10 +50,16 @@ REGISTER_COMMAND_NAME(@"status")
dispatch_group_t group = dispatch_group_create();
// Daemon status
__block BOOL driverConnected;
__block NSString *clientMode;
__block uint64_t cpuEvents, ramEvents;
__block double cpuPeak, ramPeak;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] driverConnectionEstablished:^(BOOL connected) {
driverConnected = connected;
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] clientMode:^(SNTClientMode cm) {
switch (cm) {
case SNTClientModeMonitor:
@@ -80,11 +87,10 @@ REGISTER_COMMAND_NAME(@"status")
BOOL fileLogging = ([[SNTConfigurator configurator] fileChangesRegex] != nil);
// Kext status
__block uint64_t rootCacheCount = -1, nonRootCacheCount = -1;
__block uint64_t cacheCount = -1;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] cacheCounts:^(uint64_t rootCache, uint64_t nonRootCache) {
rootCacheCount = rootCache;
nonRootCacheCount = nonRootCache;
[[self.daemonConn remoteObjectProxy] cacheCounts:^(uint64_t count) {
cacheCount = count;
dispatch_group_leave(group);
}];
@@ -103,15 +109,26 @@ REGISTER_COMMAND_NAME(@"status")
}];
// Sync status
NSString *syncURLStr = [[[SNTConfigurator configurator] syncBaseURL] absoluteString];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
NSDate *lastSyncSuccess = [[SNTConfigurator configurator] fullSyncLastSuccess];
NSString *lastSyncSuccessStr = [dateFormatter stringFromDate:lastSyncSuccess] ?: @"Never";
NSDate *lastRuleSyncSuccess = [[SNTConfigurator configurator] ruleSyncLastSuccess];
NSString *lastRuleSyncSuccessStr =
[dateFormatter stringFromDate:lastRuleSyncSuccess] ?: lastSyncSuccessStr;
BOOL syncCleanReqd = [[SNTConfigurator configurator] syncCleanRequired];
__block NSDate *fullSyncLastSuccess;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] fullSyncLastSuccess:^(NSDate *date) {
fullSyncLastSuccess = date;
dispatch_group_leave(group);
}];
__block NSDate *ruleSyncLastSuccess;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] ruleSyncLastSuccess:^(NSDate *date) {
ruleSyncLastSuccess = date;
dispatch_group_leave(group);
}];
__block BOOL syncCleanReqd = NO;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] syncCleanRequired:^(BOOL clean) {
syncCleanReqd = clean;
dispatch_group_leave(group);
}];
__block BOOL pushNotifications = NO;
if ([[SNTConfigurator configurator] syncBaseURL]) {
@@ -136,9 +153,19 @@ REGISTER_COMMAND_NAME(@"status")
fprintf(stderr, "Failed to retrieve some stats from daemon\n\n");
}
// Format dates
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
NSString *fullSyncLastSuccessStr = [dateFormatter stringFromDate:fullSyncLastSuccess] ?: @"Never";
NSString *ruleSyncLastSuccessStr =
[dateFormatter stringFromDate:ruleSyncLastSuccess] ?: fullSyncLastSuccessStr;
NSString *syncURLStr = [[[SNTConfigurator configurator] syncBaseURL] absoluteString];
if ([arguments containsObject:@"--json"]) {
NSDictionary *stats = @{
@"daemon" : @{
@"driver_connected" : @(driverConnected),
@"mode" : clientMode ?: @"null",
@"file_logging" : @(fileLogging),
@"watchdog_cpu_events" : @(cpuEvents),
@@ -147,8 +174,7 @@ REGISTER_COMMAND_NAME(@"status")
@"watchdog_ram_peak" : @(ramPeak),
},
@"kernel" : @{
@"root_cache_count" : @(rootCacheCount),
@"non_root_cache_count": @(nonRootCacheCount),
@"cache_count" : @(cacheCount),
},
@"database" : @{
@"binary_rules" : @(binaryRuleCount),
@@ -158,8 +184,8 @@ REGISTER_COMMAND_NAME(@"status")
@"sync" : @{
@"server" : syncURLStr ?: @"null",
@"clean_required" : @(syncCleanReqd),
@"last_successful_full" : lastSyncSuccessStr ?: @"null",
@"last_successful_rule" : lastRuleSyncSuccessStr ?: @"null",
@"last_successful_full" : fullSyncLastSuccessStr ?: @"null",
@"last_successful_rule" : ruleSyncLastSuccessStr ?: @"null",
@"push_notifications" : pushNotifications ? @"Connected" : @"Disconnected",
@"bundle_scanning" : @(bundlesEnabled)
},
@@ -171,13 +197,13 @@ REGISTER_COMMAND_NAME(@"status")
printf("%s\n", [statsStr UTF8String]);
} else {
printf(">>> Daemon Info\n");
printf(" %-25s | %s\n", "Driver Connected", driverConnected ? "Yes" : "No");
printf(" %-25s | %s\n", "Mode", [clientMode UTF8String]);
printf(" %-25s | %s\n", "File Logging", (fileLogging ? "Yes" : "No"));
printf(" %-25s | %lld (Peak: %.2f%%)\n", "Watchdog CPU Events", cpuEvents, cpuPeak);
printf(" %-25s | %lld (Peak: %.2fMB)\n", "Watchdog RAM Events", ramEvents, ramPeak);
printf(">>> Kernel Info\n");
printf(" %-25s | %lld\n", "Root cache count", rootCacheCount);
printf(" %-25s | %lld\n", "Non-root cache count", nonRootCacheCount);
printf(" %-25s | %lld\n", "Cache count", cacheCount);
printf(">>> Database Info\n");
printf(" %-25s | %lld\n", "Binary Rules", binaryRuleCount);
printf(" %-25s | %lld\n", "Certificate Rules", certRuleCount);
@@ -187,8 +213,8 @@ REGISTER_COMMAND_NAME(@"status")
printf(">>> Sync Info\n");
printf(" %-25s | %s\n", "Sync Server", [syncURLStr UTF8String]);
printf(" %-25s | %s\n", "Clean Sync Required", (syncCleanReqd ? "Yes" : "No"));
printf(" %-25s | %s\n", "Last Successful Full Sync", [lastSyncSuccessStr UTF8String]);
printf(" %-25s | %s\n", "Last Successful Rule Sync", [lastRuleSyncSuccessStr UTF8String]);
printf(" %-25s | %s\n", "Last Successful Full Sync", [fullSyncLastSuccessStr UTF8String]);
printf(" %-25s | %s\n", "Last Successful Rule Sync", [ruleSyncLastSuccessStr UTF8String]);
printf(" %-25s | %s\n", "Push Notifications",
(pushNotifications ? "Connected" : "Disconnected"));
printf(" %-25s | %s\n", "Bundle Scanning", (bundlesEnabled ? "Yes" : "No"));

View File

@@ -12,16 +12,17 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
@import IOKit.kext;
#import <Foundation/Foundation.h>
#import <IOKit/kext/KextManager.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommonEnums.h"
#import "SNTFileInfo.h"
#import "SNTKernelCommon.h"
#import "SNTXPCConnection.h"
@interface SNTCommandVersion : SNTCommand<SNTCommandProtocol>
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
/// Category on NSData providing the option of getting zlib or gzip compressed data.
@interface NSData (Zlib)

View File

@@ -12,20 +12,21 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
#import "SNTCommandController.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandSyncManager.h"
#import "SNTConfigurator.h"
#import "SNTDropRootPrivs.h"
#import "SNTLogging.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@interface SNTCommandSync : SNTCommand<SNTCommandProtocol>
@property SNTXPCConnection *listener;
@property MOLXPCConnection *listener;
@property SNTCommandSyncManager *syncManager;
@end
@@ -48,7 +49,7 @@ REGISTER_COMMAND_NAME(@"sync")
}
+ (NSString *)longHelpText {
return (@"If Santa is configured to synchronize with a a server, "
return (@"If Santa is configured to synchronize with a server, "
@"this is the command used for syncing.\n\n"
@"Options:\n"
@" --clean: Perform a clean sync, erasing all existing rules and requesting a"
@@ -84,12 +85,12 @@ REGISTER_COMMAND_NAME(@"sync")
#pragma mark daemon methods
- (void)syncdWithDaemonConnection:(SNTXPCConnection *)daemonConn {
- (void)syncdWithDaemonConnection:(MOLXPCConnection *)daemonConn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
// Create listener for return connection from daemon.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.listener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.listener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.listener.exportedInterface = [SNTXPCSyncdInterface syncdInterface];
self.listener.exportedObject = self.syncManager;
self.listener.acceptedHandler = ^{
@@ -108,6 +109,8 @@ REGISTER_COMMAND_NAME(@"sync")
// Now wait for the connection to come in.
if (dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC))) {
self.listener.invalidationHandler = nil;
[self.listener invalidate];
[self performSelectorInBackground:@selector(syncdWithDaemonConnection:) withObject:daemonConn];
}

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
extern NSString *const kXSRFToken;

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandSyncStage.h"

View File

@@ -16,14 +16,14 @@
#include "SNTLogging.h"
#import "MOLCertificate.h"
#import "MOLCodesignChecker.h"
#import <MOLCertificate/MOLCertificate.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "NSData+Zlib.h"
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTFileInfo.h"
#import "SNTStoredEvent.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@implementation SNTCommandSyncEventUpload
@@ -76,6 +76,8 @@
}
- (NSDictionary *)dictionaryForEvent:(SNTStoredEvent *)event {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-literal-conversion"
#define ADDKEY(dict, key, value) if (value) dict[key] = value
NSMutableDictionary *newEvent = [NSMutableDictionary dictionary];
@@ -144,6 +146,7 @@
return newEvent;
#undef ADDKEY
#pragma clang diagnostic pop
}
@end

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandSyncStage.h"

View File

@@ -12,11 +12,11 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTXPCSyncdInterface.h"
@class SNTXPCConnection;
@class MOLXPCConnection;
///
/// Handles push notifications and periodic syncing with a sync server.
@@ -37,7 +37,7 @@
/// @param daemon Set to YES if periodic syncing should occur.
/// Set to NO if a single sync should be performed. NO is default.
///
- (instancetype)initWithDaemonConnection:(SNTXPCConnection *)daemonConn
- (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn
isDaemon:(BOOL)daemon NS_DESIGNATED_INITIALIZER;
///

View File

@@ -14,10 +14,11 @@
#import "SNTCommandSyncManager.h"
@import SystemConfiguration;
#import <SystemConfiguration/SystemConfiguration.h>
#import <MOLAuthenticatingURLSession.h>
#import <MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.h>
#import <MOLFCMClient/MOLFCMClient.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTConfigurator.h"
#import "SNTCommandSyncConstants.h"
@@ -31,7 +32,6 @@
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
#import "SNTStrengthify.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
#import "SNTXPCSyncdInterface.h"
@@ -63,7 +63,7 @@ static NSString *const kFCMTargetHostIDKey = @"target_host_id";
@property MOLFCMClient *FCMClient;
@property(nonatomic) SNTXPCConnection *daemonConn;
@property(nonatomic) MOLXPCConnection *daemonConn;
@property BOOL targetedRuleSync;
@@ -89,7 +89,7 @@ static void reachabilityHandler(
#pragma mark init
- (instancetype)initWithDaemonConnection:(SNTXPCConnection *)daemonConn isDaemon:(BOOL)daemon {
- (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn isDaemon:(BOOL)daemon {
self = [super init];
if (self) {
_daemonConn = daemonConn;
@@ -178,7 +178,7 @@ static void reachabilityHandler(
}
- (void)isFCMListening:(void (^)(BOOL))reply {
reply((self.FCMClient.FCMToken != nil));
reply(self.FCMClient.isConnected);
}
#pragma mark push notification methods
@@ -205,16 +205,17 @@ static void reachabilityHandler(
[self processFCMMessage:message withMachineID:machineID];
}];
self.FCMClient.connectionErrorHandler = ^(NSError *error) {
self.FCMClient.connectionErrorHandler = ^(NSHTTPURLResponse *response, NSError *error) {
STRONGIFY(self);
LOGE(@"FCM connection error: %@", error);
if (response) LOGE(@"FCM fatal response: %@", response);
if (error) LOGE(@"FCM fatal error: %@", error);
[self.FCMClient disconnect];
self.FCMClient = nil;
[self rescheduleTimerQueue:self.fullSyncTimer secondsFromNow:kDefaultFullSyncInterval];
};
self.FCMClient.loggingBlock = ^(NSString *log) {
LOGD(@"%@", log);
LOGD(@"FCMClient: %@", log);
};
[self.FCMClient connect];
@@ -419,7 +420,7 @@ static void reachabilityHandler(
#pragma mark internal helpers
- (dispatch_source_t)createSyncTimerWithBlock:(void (^)())block {
- (dispatch_source_t)createSyncTimerWithBlock:(void (^)(void))block {
dispatch_source_t timerQueue = dispatch_source_create(
DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandSyncStage.h"

View File

@@ -16,9 +16,10 @@
#include "SNTLogging.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@implementation SNTCommandSyncPostflight
@@ -32,7 +33,7 @@
[self performRequest:[self requestWithDictionary:nil]];
dispatch_group_t group = dispatch_group_create();
void (^replyBlock)() = ^{
void (^replyBlock)(void) = ^{
dispatch_group_leave(group);
};
@@ -63,7 +64,7 @@
// Update last sync success
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] setSyncLastSuccess:[NSDate date] reply:replyBlock];
[[self.daemonConn remoteObjectProxy] setFullSyncLastSuccess:[NSDate date] reply:replyBlock];
// Wait for dispatch group
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandSyncStage.h"

View File

@@ -17,11 +17,12 @@
#include "SNTKernelCommon.h"
#include "SNTLogging.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTConfigurator.h"
#import "SNTSystemInfo.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
@implementation SNTCommandSyncPreflight
@@ -60,11 +61,17 @@
dispatch_group_leave(group);
}];
__block BOOL syncClean = NO;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] syncCleanRequired:^(BOOL clean) {
syncClean = clean;
dispatch_group_leave(group);
}];
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC));
// If user requested it or we've never had a successful sync, try from a clean slate.
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--clean"] ||
[[SNTConfigurator configurator] syncCleanRequired]) {
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--clean"] || syncClean) {
LOGD(@"Clean sync requested by user");
requestDict[kRequestCleanSync] = @YES;
}

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandSyncStage.h"

View File

@@ -14,10 +14,11 @@
#import "SNTCommandSyncRuleDownload.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTRule.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
#include "SNTLogging.h"

View File

@@ -12,16 +12,16 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
@class SNTCommandSyncState;
@class SNTXPCConnection;
@class MOLXPCConnection;
@interface SNTCommandSyncStage : NSObject
@property(readonly, nonnull) NSURLSession *urlSession;
@property(readonly, nonnull) SNTCommandSyncState *syncState;
@property(readonly, nonnull) SNTXPCConnection *daemonConn;
@property(readonly, nonnull) MOLXPCConnection *daemonConn;
/**
Initialize this stage. Designated initializer.

View File

@@ -14,18 +14,19 @@
#import "SNTCommandSyncStage.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "NSData+Zlib.h"
#import "SNTCommandSyncConstants.h"
#import "SNTCommandSyncState.h"
#import "SNTLogging.h"
#import "SNTXPCControlInterface.h"
#import "SNTXPCConnection.h"
@interface SNTCommandSyncStage ()
@property(readwrite) NSURLSession *urlSession;
@property(readwrite) SNTCommandSyncState *syncState;
@property(readwrite) SNTXPCConnection *daemonConn;
@property(readwrite) MOLXPCConnection *daemonConn;
@property BOOL xsrfFetched;
@end

View File

@@ -12,12 +12,12 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"
@class SNTCommandSyncManager;
@class SNTXPCConnection;
@class MOLXPCConnection;
/// An instance of this class is passed to each stage of the sync process for storing data
/// that might be needed in later stages.
@@ -27,7 +27,7 @@
@property NSURLSession *session;
/// Connection to the daemon control interface.
@property SNTXPCConnection *daemonConn;
@property MOLXPCConnection *daemonConn;
/// The base API URL.
@property NSURL *syncBaseURL;

View File

@@ -7,7 +7,7 @@
<key>NSHumanReadableCopyright</key>
<string>Google, Inc.</string>
<key>CFBundleIdentifier</key>
<string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
<string>com.google.santactl</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleShortVersionString</key>

View File

@@ -12,9 +12,9 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
@class SNTXPCConnection;
@class MOLXPCConnection;
@protocol SNTCommandProtocol
@@ -50,16 +50,16 @@
///
/// @note This method (or one of the methods it calls) is responsible for calling exit().
///
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn;
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(MOLXPCConnection *)daemonConn;
@end
@interface SNTCommand : NSObject<SNTCommandRunProtocol>
@property(nonatomic,readonly) SNTXPCConnection *daemonConn;
@property(nonatomic,readonly) MOLXPCConnection *daemonConn;
/// Designated initializer
- (instancetype)initWithDaemonConnection:(SNTXPCConnection *)daemonConn;
- (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn;
- (void)runWithArguments:(NSArray *)arguments;

View File

@@ -16,12 +16,12 @@
@implementation SNTCommand
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(MOLXPCConnection *)daemonConn {
id cmd = [[self alloc] initWithDaemonConnection:daemonConn];
[cmd runWithArguments:arguments];
}
- (instancetype)initWithDaemonConnection:(SNTXPCConnection *)daemonConn {
- (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn {
self = [super init];
if (self) {
_daemonConn = daemonConn;

View File

@@ -12,11 +12,11 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommand.h"
@class SNTXPCConnection;
@class MOLXPCConnection;
///
/// Responsible for maintaining the list of available commands by name, printing their help text

View File

@@ -14,7 +14,8 @@
#import "SNTCommandController.h"
#import "SNTXPCConnection.h"
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTXPCControlInterface.h"
@implementation SNTCommandController
@@ -69,8 +70,8 @@ static NSMutableDictionary *registeredCommands;
return nil;
}
+ (SNTXPCConnection *)connectToDaemonRequired:(BOOL)required {
SNTXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
+ (MOLXPCConnection *)connectToDaemonRequired:(BOOL)required {
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
if (required) {
daemonConn.invalidationHandler = ^{
@@ -94,7 +95,7 @@ static NSMutableDictionary *registeredCommands;
exit(2);
}
SNTXPCConnection *daemonConn = [self connectToDaemonRequired:[command requiresDaemonConn]];
MOLXPCConnection *daemonConn = [self connectToDaemonRequired:[command requiresDaemonConn]];
[command runWithArguments:arguments daemonConnection:daemonConn];
// The command is responsible for quitting.

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommandController.h"

View File

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

View File

@@ -12,7 +12,7 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTDatabaseTable.h"

View File

@@ -14,7 +14,8 @@
#import "SNTEventTable.h"
#import "MOLCertificate.h"
#import <MOLCertificate/MOLCertificate.h>
#import "SNTStoredEvent.h"
@implementation SNTEventTable
@@ -53,7 +54,7 @@
}
NSData *eventData;
NSNumber *idx = [rs objectForColumnName:@"idx"];
NSNumber *idx = [rs objectForColumn:@"idx"];
@try {
eventData = [NSKeyedArchiver archivedDataWithRootObject:se];
[db executeUpdate:@"UPDATE events SET eventdata=? WHERE idx=?", eventData, idx];
@@ -140,7 +141,7 @@
if (obj) {
[pendingEvents addObject:obj];
} else {
[db executeUpdate:@"DELETE FROM events WHERE idx=?", [rs objectForColumnName:@"idx"]];
[db executeUpdate:@"DELETE FROM events WHERE idx=?", [rs objectForColumn:@"idx"]];
}
}

Some files were not shown because too many files have changed in this diff Show More