Compare commits

...

77 Commits

Author SHA1 Message Date
Tom Burgin
d0ede18bf4 MOLCertificate --> 1.9 (#290) 2018-07-06 12:56:15 -04:00
Alessandro Gario
6d223aea03 Various fixes (documentation, and an additional check on the JSON received from the syncserver) (#288)
* santa-driver: Fix documentation warnings
* SantaCache: Fix documentation warnings
* santactl: Always make sure that the syncserver JSON is a dictionary
2018-07-06 09:42:22 -04:00
Alessandro Gario
f7986b0a05 Update MOLXPCConnection; add support for unprivileged XPC interfaces (#287)
* Update MOLXPCConnection; add support for unprivileged XPC interfaces

* Code review changes
2018-07-05 17:20:49 -04:00
Alessandro Gario
629e70287c Add CMake support, implement fuzzers (#284)
The new CMake project allows the user to select which SDK version
to use. The Xcode path is also configurable to support non-standard
installation paths and/or systems with multiple versions installed.

Code signing can now be configured via command line, using the
CODESIGN_IDENTITY environment variable.

New fuzzing targets (libFuzzer)
 - SantaCache
 - santactl
 - santad

New make targets:
 - tests: Runs the tests
 - fuzz: Runs the fuzzer
 - redist: Regenerates the redistributable folder
 - install: Installs Santa
2018-06-29 14:15:16 -04:00
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
Russell Hancox
103137498b santa-driver: Deny execs with names over MAXPATHLEN with appropriate errno (#231) 2018-01-24 14:02:05 -05:00
Tom Burgin
8e57e3709d SNTConfigurator: use mobileconfigs (#222)
* SNTConfigurator: use mobileconfigs

* use proper key groups

* remove state

* review updates

* review updates

* SNTConfigurator: Revert any out-of-band changes to the sync state file.

* SNTConfigurator move the file watcher to santad only
2018-01-08 12:56:24 -05:00
nguyen-phillip
bd6bd66946 santactl: Added -h and --help as synonyms for help (#225) 2017-12-05 14:16:04 -08:00
nguyen-phillip
6973dd0ec2 log the events generated by bundle hashing with action=BUNDLE (#207)
* log the events generated by bundle hashing with action=BUNDLE

* change EventLog to eventLog in SNTDaemonControlController init signature
2017-12-04 10:03:04 -08:00
Tom Burgin
2e8b08cd9e keep style fixes (#221) 2017-11-28 11:48:12 -05:00
Russell Hancox
edc8f43f42 Style fixes 2017-11-15 20:35:53 -05:00
Russell Hancox
133814cd73 santa-driver: Prevent possible infinite loop if decision requests fail to be retrieved
When enqueue'ing on the decision data queue, if the queue is full the new message will overwrite the oldest. In this scenario it's possible for that overwritten request to get stuck in an infinite loop - as far as the driver is concerned there's a request pending that the driver should be picking up and responding to but the daemon has never actually received the request. The only way out of this loop is for the file being executed to be written to. This change adds an expiration to pending requests (of 5s) so that if this scenario were to happen the pending request would be removed, breaking out of the inner decision loop to the outer loop where the request is sent to the daemon.

This change also removes a pointless dequeue in the log queue, it was intended to try and help reduce the queue size to get logs flowing again but it doesn't really help.
2017-11-15 20:35:53 -05:00
Russell Hancox
57213ee31b [santactl] Ensure reachability is released properly 2017-10-26 15:45:28 -04:00
Tom Burgin
b4fa2a394b Update .gitignore (#211)
Track files in the santa-driver dir
2017-10-16 15:20:43 -04:00
Tom Burgin
0c39342d53 santad: SNTPolicyProcessor fix nil scope check (#208)
Fixes `santactl rule --check` returning `Whitelisted (Scope)` incorrectly
2017-10-06 13:07:48 -04:00
Tom Burgin
1c95e8e25c santad: Stop ignoring CSInfoPlistFailed (#204)
It is too broad a check for the few false positive events we have seen.
2017-09-14 12:45:07 -04:00
nguyen-phillip
ff5a92772b sync: start reachability handler to retry to upload blocked event when initial upload fails (#202)
* sync: start reachability handler to retry to upload blocked event when initial upload fails

* fix indentation

* store related bundle events when server connection fails

* revert SNTBundleEventAction to BOOL

* go back to using SNTBundleEventAction in reply; make sure to send reply to avoid leaks

* fix indentation

* fix indentation
2017-09-14 12:44:32 -04:00
nguyen-phillip
bc2a17f70f santactl: added filtering to fileinfo command via --filter flag (#201)
* implemented simple filtering with fileinfo command

* Use regex filters instead of substring matching

* remove unnecessary match variable

* Update SNTCommandFileInfo.m
2017-09-14 11:21:08 -04:00
nguyen-phillip
f2e909e578 Minor refactor to merge similar methods into one: (#200)
* Merged similar methods into one:

* SNTSyncdQueue addBundleEvents: and addEvent: became addEvents:isFromBundle:
* SNTSyncdQueue backoffForBundleHash: and backoffForEvent: became backoffForPrimaryHash:
* SNTCommandSyncManager postBundleEventsToSyncServer: and postEventToSyncServer: became postEventsToSyncServer:isFromBundle:

* fix style issue

* simplify condition
2017-09-08 09:18:13 -04:00
nguyen-phillip
c3385a808c Bundle Notifications (#197)
* stub code for bundle notifications with new rules info

* get bundle rule count info from each rule, rather than initial FCM message

* Replace string literals with constants

* only update pendingNotifications for whitelist rules

* use pre-existing string constants as dictionary keys

* Remove processed entries from the notifications dictionary after we're done with them.

* fix indentation

* replace kRuleBundleHash with kFileBundleHash

* enforce serial access to the whitelistNotifications dictionary

* clarify comment

* fix queue spelling and better comments
2017-09-05 15:35:35 -04:00
Tom Burgin
8d480331ff Add Read the Docs to README (#196)
* Update README.md

* Update README.md
2017-08-18 13:29:43 -04:00
nguyen-phillip
5216f0989c santactl: Recursive fileinfo command (#191)
* temporarily gutted SNTCommandFileInfo. Added SNTCommand base class for all
of the SNTCommand* classes to inherit from.  Changed commands so that they
are consistently instantiated before being run, with a common init method.

* Put most of SNTCommandFileInfo functionality back in

* follow symlinks

* added -r and --recursive flags and updated help text

* moved humanReadableFileType to SNTFileInfo

* added back JSON output

* Fixed bundle info. Grab directory color from ENV variable.

* fixed indentation, moved stuff around

* Added SNTCommandFileInfo * back as parameter to property getters so that rule getter
doesn't have to be a special case any more.

* fixed code review issues

* added SNTCommand.h and SNTCommand.m to project

* added SNTCommand.m to build phases

* removed trailing spaces

* fixed tests for SNTCommandFileInfo and added a few more

* fix end-of-line comment spacing to conform to style guide

* Use NSBundle instead of NSWorkspace to determine if path is a bundle.

* added autorelease pool inside recursive search loop to fix bug where file listing
would abruptly stop after so many files with mach header related keys.

* removed directory headers. don't separate entries with newline when printing single key. format output based on max key length.

* an attempt at speeding things up.  also halfway fixed broken cert-index key.

* speedups via caching MOLCodeSignChecker & not using NSMutableString append*

* fix json ouput with cert-index, single key output, & cache SHA values

* reverted back to NSMutableString for building up output, since it seems slightly better
or at least no worse than using an NSMutableArray

* Don't print empty JSON objects

* fixed non-thread-safe JSON commas

* made the print dispatch group a property so it doesn't have to be passed around

* Fixed certIndex indexing bug & better error checking when parsing --cert-index argument

* prevent unsigned int overflow

* fixed logic tests broken by objc_setAssociatedObject with nil SNTFileInfo argument

* send error output to the serial print queue

* NSBundle bundleWithPath: returns an object even for non-bundle directories, so need to also check that there's a valid bundle identifier.

* Added TODO comment and fixed formatting issues

* added cached codeSignChecker property to SNTFileInfo

* rewrote SNTFileInfo's codesignChecker method to include an error reference parameter & removed @synchronized

* Removed caching of SHA values from SNTFileInfo

* use property getter/setter to access codesignCheckerError

* Change nil NSError ** arguments to NULL

* Don't try to create a new codesignChecker if there was previously an error

* Fix NSDirectoryEnumerator memory usage & don't retain self in rule getter.

The NSStrings grabbed from the directory enumerator needed a chance to be freed.

* fixed colon alignment
2017-08-18 09:56:37 -04:00
Tom Burgin
4238553a2e Docs: Start of Santa Docs (#192)
* Docs: Start of Santa Docs

* Docs: /exec()/execve()/

* Docs: /sync-server/sync server/

* Docs: review updates
2017-08-17 16:01:59 -04:00
nguyen-phillip
79662d0dcf santad/SNTEventLog: log original path of translocated apps (#194)
* log original path of translocated apps

* made handle a local variable & fixed capitalization

* Removed superfluous CFError
2017-08-17 11:09:46 -04:00
Russell Hancox
ff095bc53d KernelTests: Fix cache performance test
It was previously calculating CPU use rather than walltime which isn't really what we want to measure.
2017-08-16 16:13:45 -04:00
Russell Hancox
eefd70b2de santa-driver: Fix race condition by adding CAS op to SantaCache
Change the signature of the set method in SantaCache so that it takes an
optional previous-value parameter (and a bool indicating that this value
has been provided). If previous-value is provided, set becomes a
compare-and-swap. Also provide 2 overloads for a cleaner interface, one
with and without the previous-value parameter.
2017-08-16 16:13:45 -04:00
Russell Hancox
9b3eab67a2 santa-driver: Determine root FSID more safely
Only calculate root FSID during daemon connection. If daemon is running
there must be a root filesystem. Also check return values just in case.

Check vnode_id has been determined in VnodeCallback and SantaDriverClient
methods so that it doesn't need to be checked anywhere else.
2017-08-16 12:07:44 -04:00
Russell Hancox
54def2deb7 santa-driver: Reverse ClearCache() non_root_only default parameter 2017-08-16 12:07:44 -04:00
Russell Hancox
cd12744726 santad/santactl/santa-driver: Make status command return size of both caches 2017-08-16 12:07:44 -04:00
Russell Hancox
616fd9570f santa-driver: Split cache for root/non-root volume
Split the kernel-land cache into 2 separate caches, one for the root
volume and one for secondary volumes. When an unmount happens, clear
the non-root cache to ensure no overlap with filesystem IDs.
2017-08-16 12:07:44 -04:00
Russell Hancox
0544011ee0 [santad] Remove broken check and obsolete TODOs (#190) 2017-08-03 15:14:02 -04:00
nguyen-phillip
51920c7045 santad: modified execution log format to show path & args at end (#189)
Fixed problem where extremely long path/args obscured other log info.
2017-08-02 14:27:39 -04:00
Russell Hancox
6f417a1775 common: Remove EventDetailBundleURL key (#187)
The changes to bundle scanning mean this key isn't really necessary anymore - if a server supports bundles it tells the client during preflight, this in turn causes bundle hashes to be generated and these are used in place of the file hash when generating a detail URL. Keying bundles off the ID and version was never really a good idea anyway.
2017-08-01 12:16:37 -04:00
Russell Hancox
51034a24c6 SNTXPCConnection: Prevent crash if caller releases instance during resume (#183) 2017-07-18 16:50:32 -04:00
196 changed files with 7580 additions and 3130 deletions

3
.gitignore vendored
View File

@@ -1,9 +1,12 @@
.DS_Store
Build
santa-*
!santa-driver
!*.md
Pods
Santa.xcodeproj/xcuserdata
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

133
CMakeLists.txt Normal file
View File

@@ -0,0 +1,133 @@
cmake_minimum_required(VERSION 3.10.0)
execute_process(
COMMAND git fetch --tags --all
COMMAND git describe --tags --always --abbrev=0
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE SANTA_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND xcode-select -p
OUTPUT_VARIABLE DEFAULT_XCODE_ROOT_FOLDER
)
string(STRIP "${DEFAULT_XCODE_ROOT_FOLDER}" DEFAULT_XCODE_ROOT_FOLDER)
add_custom_target(tests)
function(AddTestTarget target_name run_as_root)
if(run_as_root)
add_custom_target(
"${target_name}_runner"
COMMAND sudo $<TARGET_FILE:${target_name}>
COMMENT "Running ${target_name}_runner as root"
)
else()
add_custom_target(
"${target_name}_runner"
COMMAND $<TARGET_FILE:${target_name}>
)
endif()
add_dependencies(tests "${target_name}_runner")
endfunction()
add_custom_target(fuzz)
function(AddFuzzTarget target_name max_len max_total_time run_as_root)
add_custom_command(TARGET "${target_name}" POST_BUILD
COMMAND codesign --force --verify --verbose --sign "${CODESIGN_IDENTITY}" $<TARGET_FILE:${target_name}>
COMMENT "Signing ${target_name} with the following identity: ${CODESIGN_IDENTITY}"
)
if(${run_as_root})
set(sudo_command "sudo")
else()
set(sudo_command "")
endif()
add_custom_target(
"${target_name}_runner"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_corpus"
COMMAND ${sudo_command} $<TARGET_FILE:${target_name}> -max_len=${max_len} -max_total_time=${max_total_time} "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_corpus" "${CMAKE_CURRENT_SOURCE_DIR}/${target_name}_seed_corpus"
COMMENT "Running fuzzer: ${target_name}"
)
add_dependencies("${target_name}_runner" "${target_name}")
add_dependencies(fuzz "${target_name}_runner")
endfunction()
function(main)
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
if(NOT DEFINED CODESIGN_IDENTITY)
if ("$ENV{CODESIGN_IDENTITY}" STREQUAL "")
message(FATAL_ERROR "Please define CODESIGN_IDENTITY - You can either use an environment variable or pass it to CMake with -DCODESIGN_IDENTITY=identity. If you are using sudo, make sure to keep the variable defined")
endif()
set(CODESIGN_IDENTITY "$ENV{CODESIGN_IDENTITY}")
endif()
if(NOT MACOSX_VERSION_MIN)
set(MACOSX_VERSION_MIN 10.9)
endif()
if(NOT MACOSX_SDK_VERSION)
set(sdk_version_name "Latest")
else()
set(sdk_version_name "${MACOSX_SDK_VERSION}")
endif()
if(NOT XCODE_ROOT_FOLDER)
set(XCODE_ROOT_FOLDER "${DEFAULT_XCODE_ROOT_FOLDER}")
endif()
message(STATUS "MACOSX_VERSION_MIN: ${MACOSX_VERSION_MIN}")
message(STATUS "MACOSX_SDK_VERSION: ${sdk_version_name}")
message(STATUS "XCODE_ROOT_FOLDER: ${XCODE_ROOT_FOLDER}")
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "SANTA_VERSION: ${SANTA_VERSION}")
add_subdirectory(CocoaPods)
add_subdirectory(Source/santad)
add_subdirectory(Source/santactl)
add_subdirectory(Source/santabs)
add_subdirectory(Source/SantaGUI)
add_subdirectory(Source/santa-driver)
add_subdirectory(Fuzzing)
add_subdirectory(Tests)
set(redist_folder_path "${CMAKE_BINARY_DIR}/redist")
add_custom_command(
OUTPUT "${redist_folder_path}/conf/install.sh"
# Copy the binaries
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_BINARY_DIR}/Source/SantaGUI/Santa.app" "${redist_folder_path}/binaries/Santa.app"
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_BINARY_DIR}/Source/santa-driver/santa-driver.kext" "${redist_folder_path}/binaries/santa-driver.kext"
# Copy the configuration files
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/Conf" "${redist_folder_path}/conf"
COMMAND "${CMAKE_COMMAND}" -E remove_directory "${redist_folder_path}/conf/Package"
COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/Docs/deployment/com.google.santa.example.mobileconfig" "${redist_folder_path}/conf"
COMMENT "Generating redistributable package"
)
add_custom_target(redist DEPENDS "${redist_folder_path}/conf/install.sh")
add_dependencies(redist santad santa-driver santactl santabs Santa)
install(FILES Conf/com.google.santad.plist DESTINATION /Library/LaunchDaemons)
install(FILES Conf/com.google.santagui.plist DESTINATION /Library/LaunchAgents)
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E echo To finalize the installation, run the following commands)")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E echo sudo /sbin/kextload /Library/Extensions/santa-driver.kext)")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E echo sudo /bin/launchctl load /Library/LaunchDaemons/com.google.santad.plist)")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E echo sudo /bin/launchctl asuser `/usr/bin/stat -f '%u' /dev/console` /bin/launchctl load /Library/LaunchAgents/com.google.santagui.plist)")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E echo Configuration guide available on ReadTheDocs - https://santa.readthedocs.io/en/latest/deployment/configuration/)")
endfunction()
main()

195
CocoaPods/CMakeLists.txt Normal file
View File

@@ -0,0 +1,195 @@
cmake_minimum_required(VERSION 3.10.0)
project(CocoaPods)
function(main)
add_custom_command(
OUTPUT "${CMAKE_SOURCE_DIR}/Pods/Manifest.lock"
COMMAND pod repo update && pod install
DEPENDS "${CMAKE_SOURCE_DIR}/Podfile"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Fetching CocoaPods dependencies"
VERBATIM
)
add_custom_target("${PROJECT_NAME}"
DEPENDS "${CMAKE_SOURCE_DIR}/Pods/Manifest.lock"
)
ImportCocoaPodsLibrary(
FMDB
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabase.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMResultSet.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabasePool.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabaseQueue.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDB.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabaseQueue.m"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabase.m"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMDatabasePool.m"
"${CMAKE_SOURCE_DIR}/Pods/FMDB/src/fmdb/FMResultSet.m"
)
target_link_libraries(FMDB PUBLIC sqlite3 "-framework Cocoa")
ImportCocoaPodsLibrary(
MOLCertificate
"${CMAKE_SOURCE_DIR}/Pods/MOLCertificate/Source/MOLCertificate"
"${CMAKE_SOURCE_DIR}/Pods/MOLCertificate/Source/MOLCertificate/MOLCertificate.m"
"${CMAKE_SOURCE_DIR}/Pods/MOLCertificate/Source/MOLCertificate/MOLCertificate.h"
)
target_link_libraries(MOLCertificate PUBLIC "-framework Security" "-framework Cocoa")
ImportCocoaPodsLibrary(
MOLCodesignChecker
"${CMAKE_SOURCE_DIR}/Pods/MOLCodesignChecker/Source/MOLCodesignChecker"
"${CMAKE_SOURCE_DIR}/Pods/MOLCodesignChecker/Source/MOLCodesignChecker/MOLCodesignChecker.h"
"${CMAKE_SOURCE_DIR}/Pods/MOLCodesignChecker/Source/MOLCodesignChecker/MOLCodesignChecker.m"
)
target_link_libraries(MOLCodesignChecker PUBLIC "-framework Security" "-framework Cocoa")
ImportCocoaPodsLibrary(
MOLAuthenticatingURLSession
"${CMAKE_SOURCE_DIR}/Pods/MOLAuthenticatingURLSession/Source/MOLAuthenticatingURLSession"
"${CMAKE_SOURCE_DIR}/Pods/MOLAuthenticatingURLSession/Source/MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.m"
"${CMAKE_SOURCE_DIR}/Pods/MOLAuthenticatingURLSession/Source/MOLAuthenticatingURLSession/MOLDERDecoder.m"
"${CMAKE_SOURCE_DIR}/Pods/MOLAuthenticatingURLSession/Source/MOLAuthenticatingURLSession/MOLDERDecoder.h"
"${CMAKE_SOURCE_DIR}/Pods/MOLAuthenticatingURLSession/Source/MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.h"
)
target_link_libraries(MOLAuthenticatingURLSession PUBLIC "-framework Security" MOLCertificate "-framework Cocoa")
ImportCocoaPodsLibrary(
MOLFCMClient
"${CMAKE_SOURCE_DIR}/Pods/MOLFCMClient/MOLFCMClient"
"${CMAKE_SOURCE_DIR}/Pods/MOLFCMClient/Source/MOLFCMClient/MOLFCMClient.m"
"${CMAKE_SOURCE_DIR}/Pods/MOLFCMClient/Source/MOLFCMClient/MOLFCMClient.h"
)
target_link_libraries(MOLFCMClient PUBLIC MOLCertificate MOLAuthenticatingURLSession "-framework Cocoa")
target_compile_options(MOLFCMClient PRIVATE -fobjc-weak)
ImportCocoaPodsLibrary(
MOLXPCConnection
"${CMAKE_SOURCE_DIR}/Pods/MOLXPCConnection/Source/MOLXPCConnection"
"${CMAKE_SOURCE_DIR}/Pods/MOLXPCConnection/Source/MOLXPCConnection/MOLXPCConnection.h"
"${CMAKE_SOURCE_DIR}/Pods/MOLXPCConnection/Source/MOLXPCConnection/MOLXPCConnection.m"
)
target_link_libraries(MOLXPCConnection PUBLIC "-framework Cocoa")
ImportCocoaPodsLibrary(
OCMock
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMExceptionReturnValueProvider.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBlockCaller.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMExpectationRecorder.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMockObject.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMArgAction.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMMacroState.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMRealObjectForwarder.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationStub.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCPartialMockObject.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMock.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMStubRecorder.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMRecorder.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationExpectation.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMFunctions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMIndirectReturnValueProvider.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCProtocolMockObject.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBlockArgCaller.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMReturnValueProvider.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBoxedReturnValueProvider.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCClassMockObject.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSObject+OCMAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationMatcher.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMPassByRefSetter.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMArg.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSNotificationCenter+OCMAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMObserverRecorder.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMNotificationPoster.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMVerifier.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMConstraint.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMLocation.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSInvocation+OCMAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSValue+OCMAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCObserverMockObject.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSMethodSignature+OCMAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMRealObjectForwarder.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMMacroState.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMArgAction.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMockObject.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMExpectationRecorder.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBlockCaller.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMExceptionReturnValueProvider.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMIndirectReturnValueProvider.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMFunctions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMStubRecorder.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMRecorder.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationExpectation.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCPartialMockObject.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationStub.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMPassByRefSetter.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMInvocationMatcher.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSObject+OCMAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCClassMockObject.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBoxedReturnValueProvider.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMBlockArgCaller.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMReturnValueProvider.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCProtocolMockObject.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSMethodSignature+OCMAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMFunctionsPrivate.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSInvocation+OCMAdditions.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCObserverMockObject.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSValue+OCMAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMLocation.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMConstraint.h"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMVerifier.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMNotificationPoster.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMObserverRecorder.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/NSNotificationCenter+OCMAdditions.m"
"${CMAKE_SOURCE_DIR}/Pods/OCMock/Source/OCMock/OCMArg.h"
)
target_link_libraries(OCMock PUBLIC "-framework Cocoa")
target_compile_options(OCMock PRIVATE -fno-objc-arc)
endfunction()
function(ImportCocoaPodsLibrary library_name source_directory)
set_source_files_properties(${ARGN} PROPERTIES GENERATED True)
add_library("${library_name}" STATIC ${ARGN})
add_dependencies("${library_name}" "${PROJECT_NAME}")
target_include_directories("${library_name}" PUBLIC
"${source_directory}"
"${CMAKE_SOURCE_DIR}/Pods/Headers/Public"
)
target_compile_options("${library_name}" PUBLIC
-Wno-deprecated -fmodules -fcxx-modules -fobjc-arc
-mmacosx-version-min=${MACOSX_VERSION_MIN}
)
if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options("${library_name}" PRIVATE -g3)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options("${library_name}" PRIVATE -O0)
else()
target_compile_options("${library_name}" PRIVATE -O3)
endif()
endfunction()
main()

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

@@ -1,12 +0,0 @@
<?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>
<!-- Minimal Configuration -->
<key>ClientMode</key>
<integer>1</integer>
<!-- For documentation of other keys, see the following URL:
https://github.com/google/santa/wiki/Configuration-Keys -->
</dict>
</plist>

View File

@@ -39,9 +39,16 @@ GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
mkdir -p /usr/local/bin
/bin/ln -s /Library/Extensions/santa-driver.kext/Contents/MacOS/santactl /usr/local/bin
if [ ! -d /var/db/santa ] ; then
mkdir /var/db/santa
fi
cp ${SOURCE}/conf/com.google.santa.example.mobileconfig /var/db/santa
/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

@@ -6,6 +6,15 @@
[ "$EUID" != 0 ] && printf "%s\n" "This requires running as root/sudo." && exit 1
if [[ -d "binaries" ]]; then
SOURCE="."
elif [[ -d "../binaries" ]]; then
SOURCE=".."
else
echo "Can't find binaries, run install.sh from inside the conf directory" 1>&2
exit 1
fi
/bin/launchctl remove com.google.santad
sleep 1
/sbin/kextunload -b com.google.santa-driver >/dev/null 2>&1
@@ -19,7 +28,9 @@ 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
#/bin/rm -f /var/log/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

@@ -0,0 +1,179 @@
# 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: 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 Profile
| Key | Value Type | Description |
| ----------------------------- | ---------- | ---------------------------------------- |
| ClientMode* | Integer | 1 = MONITOR, 2 = LOCKDOWN, defaults to MONITOR |
| FileChangesRegex* | String | The regex of paths to log file changes. Regexes are specified in ICU format. |
| WhitelistRegex* | String | A regex to whitelist if the binary or certificate scopes did not allow execution. Regexes are specified in ICU format. |
| BlacklistRegex* | String | A regex to blacklist if the binary or certificate scopes did not block an execution. Regexes are specified in ICU format. |
| EnablePageZeroProtection | Bool | Enable `__PAGEZERO` protection, defaults to YES. If this flag is set to YES, 32-bit binaries that are missing the `__PAGEZERO` segment will be blocked even in MONITOR mode, **unless** the binary is whitelisted by an explicit rule. |
| MoreInfoURL | String | The URL to open when the user clicks "More Info..." when opening Santa.app. If unset, the button will not be displayed. |
| EventDetailURL | String | See the [EventDetailURL](#eventdetailurl) section below. |
| EventDetailText | String | Related to the above property, this string represents the text to show on the button. |
| UnknownBlockMessage | String | In Lockdown mode this is the message shown to the user when an unknown binary is blocked. If this message is not configured a reasonable default is provided. |
| BannedBlockMessage | String | This is the message shown to the user when a binary is blocked because of a rule if that rule doesn't provide a custom message. If this is not configured a reasonable default is provided. |
| ModeNotificationMonitor | String | The notification text to display when the client goes into Monitor mode. Defaults to "Switching into Monitor mode". |
| ModeNotificationLockdown | String | The notification text to display when the client goes into Lockdown mode. Defaults to "Switching into Lockdown mode". |
| SyncBaseURL* | String | The base URL of the sync server. |
| ClientAuthCertificateFile | String | If set, this contains the location of a PKCS#12 certificate to be used for sync authentication. |
| ClientAuthCertificatePassword | String | Contains the password for the PKCS#12 certificate. |
| ClientAuthCertificateCN | String | If set, this is the Common Name of a certificate in the System keychain to be used for sync authentication. The corresponding private key must also be in the keychain. |
| ClientAuthCertificateIssuerCN | String | If set, this is the Issuer Name of a certificate in the System keychain to be used for sync authentication. The corresponding private key must also be in the keychain. |
| ServerAuthRootsData | Data | If set, this is valid PEM containing one or more certificates to be used to evaluate the server's SSL chain, overriding the list of trusted CAs distributed with the OS. |
| ServerAuthRootsFile | String | The same as the above but is a path to a file on disk containing the PEM data. |
| MachineOwner | String | The machine owner. |
| MachineID | String | The machine ID. |
| MachineOwnerPlist | String | The path to a plist that contains the MachineOwnerKey / value pair. |
| 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. |
*overridable by the sync server: run `santactl status` to check the current running config
##### EventDetailURL
When the user gets a block notification, a button can be displayed which will take them to a web page with more information about that event.
This property contains a kind of format string to be turned into the URL to send them to. The following sequences will be replaced in the final URL:
| Key | Description |
| ------------ | ---------------------------------------- |
| %file_sha% | SHA-256 of the file that was blocked |
| %machine_id% | ID of the machine |
| %username% | The executing user |
| %bundle_id% | Bundle ID of the binary, if applicable |
| %bundle_ver% | Bundle version of the binary, if applicable |
For example: `https://sync-server-hostname/%machine_id%/%file_sha%`
##### Example Configuration Profile
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>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>
```
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 |
| ------------------------------ | ---------- | ---------------------------------------- |
| client_mode | String | MONITOR or LOCKDOWN, defaults to MONITOR. |
| clean_sync** | Bool | If set to `True` Santa will clear all local rules and download a fresh copy from the sync-server. Defaults to `False`. |
| batch_size | Integer | The number of rules to download or events to upload per request. Multiple requests will be made if there is more work than can fit in single request. Defaults to 50. |
| upload_logs_url** | String | If set, the endpoint to send Santa's current logs. No default. |
| whitelist_regex | String | Same as the "Local Configuration" WhitelistRegex. No default. |
| blacklist_regex | String | Same as the "Local Configuration" BlacklistRegex. No default. |
| fcm_token* | String | The FCM token used by Santa to listen for FCM messages. Unique for every machine. No default. |
| fcm_full_sync_interval* | Integer | The full sync interval if a fcm_token is set. Defaults to 14400 secs (4 hours). |
| fcm_global_rule_sync_deadline* | Integer | The max time to wait before performing a rule sync when a global rule sync FCM message is received. This allows syncing to be staggered for global events to avoid spikes in server load. Defaults to 600 secs (10 min). |
| bundles_enabled* | Bool | If set to `True` the bundle scanning feature is enabled. Defaults to `False`. |
*Held only in memory. Not persistent upon process restart.
**Performed once per preflight run (if set).

BIN
Docs/details/block.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

141
Docs/details/events.md Normal file
View File

@@ -0,0 +1,141 @@
# Events
Events are a defined set of data, core to how Santa interacts with a sync server. Events are generated when there is a blocked `execve()` while in Lockdown or Monitor mode. Events are also generated in Monitor mode for an `execve()` that was allowed to run, but would have been blocked in Lockdown mode. This allows an admin to roll out Santa to their macOS fleet in Monitor mode but still collect meaningful data. The events collected while in Monitor mode can be used to build a reasonably comprehensive whitelist of signing certificates and binaries before switching the fleet to Lockdown mode.
##### Event Data
Events begin their life as an [SNTStoredEvent](https://github.com/google/santa/blob/master/Source/common/SNTStoredEvent.h) object. The SNTStoredEvent class is just a simple storage class that has properties for all the relevant bits of information. More importantly the class implements the [NSSecureCoding](https://developer.apple.com/documentation/foundation/nssecurecoding?language=objc) protocol. This allows the objects to be encoded and decoded for storage in the events sqlite3 database on disk and sent over XPC to another process.
Events are temporarily stored in a database until they are uploaded. The format is subject the change; accessing the events database directly will most likely break in future releases. If direct access to the events database is required, raise a [issue on the Santa GitHub](https://github.com/google/santa/issues).
###### JSON
Before an event is uploaded to a sync server, the event data is copied into a JSON blob. Here is an example of Firefox being blocked and sent for upload:
```json
{
"events": [
{
"file_path": "/var/folders/l5/pd9rhsp54s79_9_qcy746_tw00b_4p/T/AppTranslocation/254C1357-7461-457B-B734-A0FDAF0F26D9/d/Firefox.app/Contents/MacOS",
"file_bundle_version": "5417.6.28",
"parent_name": "launchd",
"logged_in_users": [
"bur"
],
"quarantine_timestamp": 0,
"signing_chain": [
{
"cn": "Developer ID Application: Mozilla Corporation (43AQ936H96)",
"valid_until": 1652123338,
"org": "Mozilla Corporation",
"valid_from": 1494270538,
"ou": "43AQ936H96",
"sha256": "96f18e09d65445985c7df5df74ef152a0bc42e8934175a626180d9700c343e7b"
},
{
"cn": "Developer ID Certification Authority",
"valid_until": 1801519935,
"org": "Apple Inc.",
"valid_from": 1328134335,
"ou": "Apple Certification Authority",
"sha256": "7afc9d01a62f03a2de9637936d4afe68090d2de18d03f29c88cfb0b1ba63587f"
},
{
"cn": "Apple Root CA",
"valid_until": 2054670036,
"org": "Apple Inc.",
"valid_from": 1146001236,
"ou": "Apple Certification Authority",
"sha256": "b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024"
}
],
"file_bundle_name": "Firefox",
"executing_user": "bur",
"ppid": 1,
"file_bundle_path": "/var/folders/l5/pd9rhsp54s79_9_qcy746_tw00b_4p/T/AppTranslocation/254C1357-7461-457B-B734-A0FDAF0F26D9/d/Firefox.app",
"file_name": "firefox",
"execution_time": 1501691337.059514,
"file_sha256": "dd78f456a0929faf5dcbb6d952992d900bfdf025e1e77af60f0b029f0b85bf09",
"decision": "BLOCK_BINARY",
"file_bundle_id": "org.mozilla.firefox",
"file_bundle_version_string": "54.0.1",
"pid": 49368,
"current_sessions": [
"bur@console",
"bur@ttys000",
"bur@ttys001",
"bur@ttys002",
"bur@ttys003",
"bur@ttys004"
]
}
]
}
```
##### Event Lifecycle
1. santad generates a new event
2. santad compares, or adds if not present, the event's SHA-256 file hash to an in-memory cache with a timeout of 10 min. If an event with an matching hash is present in cache, the event is dropped.
3. santad saves the event to `/var/db/santa/events.db` with a unique ID assigned as the key.
4. santad sends an XPC message to the santactl daemon. The message contains the event with instructions to upload the event immediately. This is non-blocking and is performed on a background thread.
##### Bundle Events
Bundle events are a special type of event that are generated when a sync server supports receiving the associated bundle events, instead of just the original event. For example: `/Applications/Keynote.app/Contents/MacOS/Keynote` is blocked and an event representing the binary is uploaded. A whitelist rule is created for that one binary. Great, you can now run `/Applications/Keynote.app/Contents/MacOS/Keynote`, but what about all the other supporting binaries contained in the bundle? You would have to wait until they are executed until an event would be generated. It is very common for a bundle to contain multiple binaries, as shown here with Keynote.app. Waiting to get a block is not a very good user experience.
```sh
⇒ santactl bundleinfo /Applications/Keynote.app
Hashing time: 1047 ms
9 events found
BundleHash: b475667ab1ab6eddea48bfc2bed76fcef89b8f85ed456c8068351292f7cb4806
BundleID: com.apple.iWork.Keynote
SHA-256: be3aa404ee79c2af863132b93b0eedfdbc34c6e35d4fda2ade6dd637692ead84
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.MovieCompatibilityConverter.xpc/Contents/MacOS/com.apple.iWork.MovieCompatibilityConverter
BundleID: com.apple.iWork.Keynote
SHA-256: 3b2582fd5e7652b653276b3980c248dc973e8082e9d0678c96a08d7d1a8366ba
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.PICTConverter.xpc/Contents/MacOS/com.apple.iWork.PICTConverter
BundleID: com.apple.iWork.Keynote
SHA-256: f1bf3be05d511d7c7f651cf7b130d4977f8d28d0bfcd7c5de4144b95eaab7ad7
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor
BundleID: com.apple.iWork.Keynote
SHA-256: b59bc8548c91088a40d9023abb5d22fa8731b4aa17693fcb5b98c795607d219a
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.BitmapTracer.xpc/Contents/MacOS/com.apple.iWork.BitmapTracer
BundleID: com.apple.iWork.Keynote
SHA-256: 08cb407f541d867f1a63dc3ae44eeedd5181ca06c61df6ef62b5dc7192951a4b
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCUtilities32
BundleID: com.apple.iWork.Keynote
SHA-256: b965ae7be992d1ce818262752d0cf44297a88324a593c67278d78ca4d16fcc39
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor.TCUtilities32
BundleID: com.apple.iWork.Keynote
SHA-256: 59668dc27314f0f6f5daa5f02b564c176f64836c88e2dfe166e90548f47336f1
Path: /Applications/Keynote.app/Contents/MacOS/Keynote
BundleID: com.apple.iWork.Keynote
SHA-256: 7ce324f919b14e14d327004b09f83ca81345fd4438c87ead4b699f89e9485595
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.ExternalResourceValidator.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceValidator
BundleID: com.apple.iWork.Keynote
SHA-256: 6b47f551565d886388eeec5e876b6de9cdd71ef36d43b0762e6ebf02bdd8515d
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceAccessor
```
Bundle events provide a mechanism to generate and upload events for all the executable Mach-O binaries within a bundle. To enable bundle event generation a configuration must be set in the preflight sync stage on the sync server. Once set the sync server can use bundle events to drive a better user experience.
Bundle events can be differentiated by the existence of these fields:
| Field | Value |
| ------------------------ | ---------------------------------------- |
| decision | BUNDLE_BINARY |
| file_bundle_hash | Super Hash of all binary hashes |
| file_bundle_hash_millis | The time in milliseconds it took to find all of the binaries, hash and produce a super hash |
| file_bundle_binary_count | Number of binaries within the bundle |
To avoid redundant uploads of a bundle event Santa will wait for the sync server to ask for them. The server will respond to event uploads with a request like this:
| Field | Value |
| ---------------------------- | ---------------------------------------- |
| event_upload_bundle_binaries | An array of bundle hashes that the sync server needs to be uploaded |
When santactl receives this type of request, it sends an XPC reply to santad to save all the bundle events to the events.db. It then attempts to upload all the bundle events, purging the successes from the events.db. Any failures will be uploaded during the next full sync.

43
Docs/details/ipc.md Normal file
View File

@@ -0,0 +1,43 @@
# Interprocess Communication (IPC)
Most IPC within Santa is done by way of Apple's [XPC](https://developer.apple.com/documentation/xpc?language=objc). Santa wraps [NSXPCConnection](https://developer.apple.com/documentation/foundation/nsxpcconnection?language=objc) to provide client multiplexing, signature validation of connecting clients and forced connection establishment. This is called SNTXPCConnection.
Communication between santad and santa-driver (KEXT) is done with a [IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc) subclass and IOKit/IOKitLib.h functions.
##### Who starts who?
The santad and Santa (GUI) processes are both started and kept alive by launchd as a LaunchDaemon and a LaunchAgent, respectively. This means santad runs as root and Santa (GUI) runs as the console user.
There can be multiple Santa (GUI) processes running, one per user logged into the GUI (assuming fast-user switching is enabled). While multiple processes might be running, only the one for the user currently logged-in will be connected to santad and receiving notifications.
When using a sync server, the santactl process is started by santad. Before the new process starts, all privileges are dropped. santactl runs as _nobody_.
The santabs process is started by launchd via an XPC service connection from santad. XPC services inherit their initiator's privileges meaning santabs runs as root, which is necessary to ensure it has permission to read all files.
| Process | Parent Process | Running User |
| -------- | -------------- | ------------ |
| santad | launchd | root |
| Santa | launchd | user |
| santactl | santad | nobody |
| santabs | launchd | root |
##### Who communicates with who?
In short, santad has two-way communication with every other process. In addition, Santa and santabs have two-way communication between each other. For other combinations, there is no direct communication.
![Santa IPC](santa_ipc.png)
##### SNTXPCConnection and two way communication
`SNTXPCConnection` enforces a server / client model for XPC connections. This allows for strong signature validation and forced connection establishment. The only problem with this model is the lack of two-way communication. For example, process A can call methods on process B and retrieve a response, but process B cannot call methods on process A.
To accomplish two-way communication, the following approach can be used:
1. Process A creates a server with an anonymous `NSXPCListener`.
2. Process A sends the anonymous `NSXPCListenerEndpoint` to process B over an already established `SNTXPCConnection`.
3. Process B can now communicate directly with process A.
This is a powerful notion. It enables forced connection establishment between both processes, which is critical when reliability is a concern.

30
Docs/details/logs.md Normal file
View File

@@ -0,0 +1,30 @@
# Logs
Santa currently logs to `/var/db/santa/santa.log` by default. All executions and disk mounts are logged here. File operations can also be configured to be logged. See the `FileChangesRegex` key in the [configuration.md](../deployment/configuration.md) document.
To view the logs:
```sh
tail -F /var/db/santa/santa.log
```
The `-F` will continue watching the path even when the current file fills up and rolls over.
##### macOS Unified Logging System (ULS)
Currently all of the most recent releases of Santa are built with the macOS 10.11 SDK. This allows Santa to continue to log to Apple System Logger (ASL) instead of ULS. However, on macOS 10.12+ all of the Kernel logs are sent to ULS. See the KEXT Logging section below for more details.
If you are building Santa yourself and using the macOS 10.12+ SDKs, Santa's logs will be sent to ULS.
Work is currently underway to bypass ASL and ULS altogether, allowing Santa to continue logging to `/var/db/santa/santa.log`. This change will also allow us to add alternative logging formats, like Protocol Buffer or JSON.
##### KEXT Logging
Streaming logs from the santa-driver KEXT does not work properly. Logs are generated but they will likely be garbled or show inaccurate data.
Instead, `show` can be used to view the santa-driver KEXT logs:
```sh
/usr/bin/log show --info --debug --predicate 'senderImagePath == "/Library/Extensions/santa-driver.kext/Contents/MacOS/santa-driver"'
```

53
Docs/details/mode.md Normal file
View File

@@ -0,0 +1,53 @@
# Mode
Santa can run in one of two modes, Lockdown or Monitor. To check the current status run the following command:
```sh
⇒ santactl status
>>> Daemon Info
Mode | Monitor
File Logging | Yes
Watchdog CPU Events | 0 (Peak: 13.59%)
Watchdog RAM Events | 0 (Peak: 31.49MB)
>>> Kernel Info
Root cache count | 107
Non-root cache count | 0
>>> Database Info
Binary Rules | 5
Certificate Rules | 2
Events Pending Upload | 0
>>> Sync Info
Sync Server | https://sync-server-hostname.com
Clean Sync Required | No
Last Successful Full Sync | 2017/08/02 21:44:17 -0400
Last Successful Rule Sync | 2017/08/02 21:44:17 -0400
Push Notifications | Connected
Bundle Scanning | Yes
```
##### Monitor mode
The default mode. Running Santa in Monitor Mode will stop any binaries matching blacklist rules, but will not stop unknown binaries from running. This is a flexible state, allowing virtually zero user interruption but still gives protection against known blacklisted binaries. In addition execution events that would have been blocked in Lockdown mode are generated and can be collected and analyzed by a sync server.
##### Lockdown mode
Running Santa in Lockdown Mode will stop all blacklisted binaries and additionally will prevent all unknown binaries from running. This means that if the binary has no rules or scopes that apply, then it will be blocked.
##### Changing Modes
There are two ways to change the running mode: changing the configuration profile and with a sync server configuration.
###### Change modes with the configuration profile
Set the `ClientMode` in your configuration profile to the integer value `1` for MONITOR or `2` for LOCKDOWN.
```xml
<key>ClientMode</key>
<integer>1</integer>
```
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.
###### 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`.

BIN
Docs/details/push.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

104
Docs/details/rules.md Normal file
View File

@@ -0,0 +1,104 @@
# Rules
Rules provide the primary evaluation mechanism for whitelisting and blacklisting binaries with Santa on macOS. There are two types of rules: binary and certificate.
##### Binary Rules
Binary rules use the SHA-256 hash of the entire binary as an identifier. This is the most specific rule in Santa. Even a small change in the binary will alter the SHA-256 hash, invalidating the rule.
##### Certificate Rules
Certificate rules are formed from the SHA-256 fingerprint of an X.509 leaf signing certificate. This is a powerful rule type that has a much broader reach than an individual binary rule . A signing certificate can sign any number of binaries. Whitelisting or blacklisting just a few key signing certificates can cover the bulk of an average user's binaries. The leaf signing certificate is the only part of the chain that is evaluated. Though the whole chain is available for viewing.
```sh
⇒ santactl fileinfo /Applications/Dropbox.app --key "Signing Chain"
Signing Chain:
1. SHA-256 : 2a0417257348a20f96c9de0486b44fcc7eaeaeb7625b207591b8109698c02dd2
SHA-1 : 86ec91f726ba9caa09665b2109c49117f0b93134
Common Name : Developer ID Application: Dropbox, Inc.
Organization : Dropbox, Inc.
Organizational Unit : G7HH3F8CAK
Valid From : 2012/06/19 16:10:30 -0400
Valid Until : 2017/06/20 16:10:30 -0400
2. SHA-256 : 7afc9d01a62f03a2de9637936d4afe68090d2de18d03f29c88cfb0b1ba63587f
SHA-1 : 3b166c3b7dc4b751c9fe2afab9135641e388e186
Common Name : Developer ID Certification Authority
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2012/02/01 17:12:15 -0500
Valid Until : 2027/02/01 17:12:15 -0500
3. SHA-256 : b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024
SHA-1 : 611e5b662c593a08ff58d14ae22452d198df6c60
Common Name : Apple Root CA
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2006/04/25 17:40:36 -0400
Valid Until : 2035/02/09 16:40:36 -0500
```
If you wanted to whitelist or blacklist all software signed with this perticular Dropbox signing certificate you would use the leaf SHA-256 fingerprint.
`2a0417257348a20f96c9de0486b44fcc7eaeaeb7625b207591b8109698c02dd2`
Santa does not evaluate the `Valid From` or `Valid Until` fields, nor does it check the Certificate Revocation List (CRL) or the Online Certificate Status Protocol (OCSP) for revoked certificates. Adding rules for the certificate chain's intermediates or roots has no effect on binaries signing by a leaf. Santa ignores the chain and is only concerned with the leaf certificate's SHA-256 hash.
##### Rule Evaluation
When a process is trying to `execve()` santad retrieves information on the binary, including a hash of the entire file and the signing chain (if any). The hash and signing leaf certificate are then passed through the [SNTPolicyProcessor](https://github.com/google/santa/blob/master/Source/santad/SNTPolicyProcessor.h). Rules are evaluated from most specific to least specific. First binary (either whitelist or blacklist), then certificate (either whitelist or blacklist). If no rules are found that apply, scopes are then searched. See the [scopes.md](scopes.md) document for more information on scopes.
You can use the `santactl fileinfo` command to check the status of any given binary on the filesystem.
###### Whitelisted with a Binary Rule
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key Rule
Whitelisted (Binary)
```
###### Whitelisted with a Certificate Rule
```sh
⇒ santactl fileinfo /Applications/Safari.app --key Rule
Whitelisted (Certificate)
```
###### Blacklisted with a Binary Rule
```sh
⇒ santactl fileinfo /usr/bin/yes --key Rule
Blacklisted (Binary)
```
###### Blacklisted with a Certificate Rule
```sh
⇒ santactl fileinfo /Applications/Malware.app --key Rule
Blacklisted (Certificate)
```
You can also check arbitrary SHA-256 binary and certificate hashes for rules. The rule verb needs to be run with root privileges.
For checking the SHA-256 hash of `/usr/bin/yes`:
```sh
sudo santactl rule --check --sha256 $(santactl fileinfo --key SHA-256 /usr/bin/yes)
Blacklisted (Binary)
```
For checking the SHA-256 hash of `/usr/bin/yes ` signing certificate:
```sh
⇒ sudo santactl rule --check --certificate --sha256 $(santactl fileinfo --cert-index 1 --key SHA-256 /usr/bin/yes)
Whitelisted (Certificate)
```
##### Built-in rules
To avoid blocking any Apple system binaries or Santa binaries, santad will create 2 immutable certificate rules at startup:
* The signing certificate santad is signed with
* The signing certificate launchd is signed with
By creating these two rules at startup, Santa should never block critical Apple system binaries or other Santa components.

View File

@@ -0,0 +1,94 @@
# santa-driver
santa-driver is a macOS [kernel extension](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptIntro/introduction.html) (KEXT) that makes use of the [Kernel Authorization](https://developer.apple.com/library/content/technotes/tn2127/_index.html) (Kauth) KPI. This allows santa-driver to listen for events and either deny or defer the decision of those events. The santa-driver acts as an intermediary layer between Kauth and santad, with some caching to lower the overhead of decision making.
##### Kauth
santa-driver utilizes two Kauth scopes `KAUTH_SCOPE_VNODE` and `KAUTH_SCOPE_FILEOP `. It registers itself with the Kauth API by calling `kauth_listen_scope()` for each scope. This function takes three arguments:
* `const char *scope`
* `kauth_scope_callback_t _callback`_
* `void *contex`
It returns a `kauth_listener_t` that is stored for later use, in Santa's case to stop listening.
###### KAUTH_SCOPE_VNODE
Here is how santa-driver starts listening for `KAUTH_SCOPE_VNODE` events.
```c++
vnode_listener_ = kauth_listen_scope(
KAUTH_SCOPE_VNODE, vnode_scope_callback, reinterpret_cast<void *>(this));
```
The function `vnode_scope_callback` is called for every vnode event. There are many types of vnode events, they complete list can be viewed in the kauth.h. There are many types of vnode events, the complete list can be viewed in kauth.h. Santa is only concerned with regular files generating `KAUTH_VNODE_EXECUTE` [1] and `KAUTH_VNODE_WRITE_DATA` events. All non-regular files and unnecessary vnode events are filtered out.
Here is how santa-driver stops listening for `KAUTH_SCOPE_VNODE` events:
```c++
kauth_unlisten_scope(vnode_listener_);
```
[1] `KAUTH_VNODE_EXECUTE` events that do not have the `KAUTH_VNODE_ACCESS` advisory bit set.
###### KAUTH_SCOPE_FILEOP
Santa also listens for file operations, this is mainly used for logging [1] and cache invalidation.
* `KAUTH_FILEOP_DELETE`, `KAUTH_FILEOP_RENAME`, `KAUTH_FILEOP_EXCHANGE` and `KAUTH_FILEOP_LINK` are logged
* `KAUTH_FILEOP_EXEC` is used to log `execve()`s. Since the `KAUTH_VNODE_EXECUTE` is used to allow or deny an `execve()` the process arguments have not been setup yet. Since `KAUTH_FILEOP_EXEC` is triggered after an `execve()` it is used to log the `execve()`.
[1] `KAUTH_FILEOP_CLOSE` is used to invalidate that file's representation in the cache. If a file has changed it needs to be re-evalauted. This is particularly necessary for files that were added to the cache with an action of allow.
##### Driver Interface
santa-driver implements an [IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc) subclass and santad interacts with it through IOKit/IOKitLib.h functions.
[//]: # "TODO(bur, rah) Flesh out the details"
##### Cache
To aid in performance, santa-driver utilizes a caching system to hold the state of all observed `execve()` events.
###### Key
The key is a `uint64_t`. The top 32 bits hold the filesystem ID, while the bottom 32 bits hold the file unique ID. Together we call this the vnode_id.
```c++
uint64_t vnode_id = (((uint64_t)fsid << 32) | fileid);
```
###### Value
The value is a `uint64_t` containing the action necessary, along with the decision timestamp. The action is stored in the top 8 bits. The decision timestamp is stored in the remaining 56 bits.
```c++
santa_action_t action = (santa_action_t)(cache_val >> 56);
uint64_t decision_time = (cache_val & ~(0xFF00000000000000));
```
The possible actions are:
| Actions | Expiry Time | Description |
| ----------------------- | ---------------- | ---------------------------------------- |
| `ACTION_REQUEST_BINARY` | None | Awaiting an allow or deny decision from santad. |
| `ACTION_RESPOND_ALLOW` | None | Allow the `execve()` |
| `ACTION_RESPOND_DENY` | 500 milliseconds | Deny the `execve()`, but re-evalaute after 500 milliseconds. If someone is trying to run a banned binary continually every millisecond for example, only 2 evaluation requests to santad for would occur per second. This mitigates a denial of service type attack on santad. |
###### Invalidation
Besides the expiry time for individual entries, the entire cache will be cleared if any of the following events takes place:
* Addition of a blacklist rule
* Addition of a blacklist regex scope
* Cache fills up. This defaults to `5000` entries for the root volume and `500` for all other mounted volumes.
To view the current kernel cache count see the "Kernel info" section of `santactl status`:
```sh
⇒ santactl status
>>> Kernel Info
Root cache count | 107
Non-root cache count | 0
```

11
Docs/details/santa-gui.md Normal file
View File

@@ -0,0 +1,11 @@
# Santa GUI
The Santa GUI process is pretty simple. It's only job is the display user GUI notifications. There are two types of notifications it can display:
A notification when an `execve()` is blocked.
![Block](block.png)
Notifications when specific rules arrive (when using FCM for push notifications).
![Notification](push.png)

BIN
Docs/details/santa_ipc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

44
Docs/details/santabs.md Normal file
View File

@@ -0,0 +1,44 @@
# santabs
The santabs process is an XPC service for the santa-driver.kext bundle, meaning only binaries within that bundle can launch santabs. It will be launched with the same privileges as its calling process. Currently, santad is the only caller of santabs, so santabs runs as root.
##### Events
The santabs process is quite simple and only does one thing: it generates non-execution events for the contents of a bundle.
When there is an `execve()` that is blocked within a bundle, a few actions take place:
1. The highest ancestor bundle in the tree is found
* So `/Applications/DVD Player.app/Contents/MacOS/DVD Player` would be `/Applications/DVD Player.app`
* Or `/Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension` would be `/Applications/Safari.app`
2. The ancestor bundle is then searched for Mach-O executables
* For Safari that would currently be 4 binaries
* ```sh
Hashing time: 53 ms
4 events found
BundleHash: 718773556ca5ea798f984fde2fe1a5994f175900b26d2964c9358a0f469a4ac6
BundleID: com.apple.Safari
SHA-256: ea872e83a518ce442ed050c4408a448d915e2bae90ef8455ce7805448d864a3e
Path: /Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension
BundleID: com.apple.Safari
SHA-256: 1a43283857b1822164f82af274c476204748c0a2894dbcaa11ed17f78e0273cc
Path: /Applications/Safari.app/Contents/MacOS/Safari
BundleID: com.apple.Safari
SHA-256: ab0ac54dd90144931b681d1e84e198c6510be44ac5339437bc004e60777af7ba
Path: /Applications/Safari.app/Contents/Resources/appdiagnose
BundleID: com.apple.Safari
SHA-256: f49c5aa3a7373127d0b4945782b1fa375dd3707d66808fd66b7c0756430defa8
Path: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.BrowserDataImportingService.xpc/Contents/MacOS/com.apple.Safari.BrowserDataImportingService
```
3. Events are created for each binary and the bundle hash is calculated
4. These events are sent to the sync server for processing
##### Bundle Hash
The found events are sorted by their file SHA-256 hash. The hashes are concatenated and then SHA-256 hashed. This is now a strong indicator on what Mach-O executables were within the bundle at the time of scan. This can then be verified by the sync server when deciding to generate rules.

425
Docs/details/santactl.md Normal file
View File

@@ -0,0 +1,425 @@
# santactl
This may be the most complex part of Santa. It does two types of work:
1. It contains all of the code and functionality for syncing with a sync-server.
2. It can be used to view the state and configuration of Santa as a whole. It can also inspect individual files. When running without a sync server it also a supported method of managing the rules database.
The details of santactl's syncing functionality are covered in the syncing.md document. This document will cover the status work that santactl performs.
##### status
To view the status of Santa run `santactl status`
```sh
⇒ santactl status
>>> Daemon Info
Mode | Monitor
File Logging | Yes
Watchdog CPU Events | 0 (Peak: 2.19%)
Watchdog RAM Events | 0 (Peak: 29.45MB)
>>> Kernel Info
Kernel cache count | 123
>>> Database Info
Binary Rules | 321
Certificate Rules | 123
Events Pending Upload | 0
>>> Sync Info
Sync Server | https://sync-server.com/santa/
Clean Sync Required | No
Last Successful Full Sync | 2017/08/10 15:05:32 -0400
Last Successful Rule Sync | 2017/08/10 15:29:21 -0400
Push Notifications | Connected
Bundle Scanning | Yes
```
The status command also has the ability to print JSON output `santactl status --json`
```sh
⇒ santactl status --json
{
"kernel" : {
"cache_count" : 123
},
"daemon" : {
"watchdog_ram_events" : 0,
"watchdog_ram_peak" : 29.44921875,
"watchdog_cpu_events" : 0,
"file_logging" : true,
"mode" : "Monitor",
"watchdog_cpu_peak" : 2.188006666666666
},
"database" : {
"events_pending_upload" : 0,
"certificate_rules" : 123,
"binary_rules" : 321
},
"sync" : {
"last_successful_rule" : "2017\/08\/10 15:29:21 -0400",
"push_notifications" : "Connected",
"bundle_scanning" : true,
"clean_required" : false,
"server" : "https:\/\//sync-server.com\/santa\/",
"last_successful_full" : "2017\/08\/10 15:05:32 -0400"
}
}
```
##### version
To view all of the component versions `santactl version`
```sh
⇒ santactl version
santa-driver | 0.9.19
santad | 0.9.19
santactl | 0.9.19
SantaGUI | 0.9.19
```
Again, a JSON version is available `santactl version --json`
```sh
⇒ santactl version --json
{
"santa-driver" : "0.9.19",
"santad" : "0.9.19",
"SantaGUI" : "0.9.19",
"santactl" : "0.9.19"
}
```
##### fileinfo
The fileinfo verb is very powerful and can be used to tease out just about anything you wish to know about a file, with respect to the domain of Santa.
Here is an example of using `santactl fileinfo ` to inspect the main executable within `/Applications/Hex Fiend.app`.
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app
Path : /Applications/Hex Fiend.app/Contents/MacOS/Hex Fiend
SHA-256 : efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
SHA-1 : 5585e6fb94eace1bd37da9a0a2f928e992d7c60c
Bundle Name : Hex Fiend
Bundle Version : 170205
Bundle Version Str : 2.5
Download Referrer URL: http://ridiculousfish.com/hexfiend/
Download URL : http://ridiculousfish.com/hexfiend/files/Hex_Fiend_2.5.dmg
Download Timestamp : 2017/06/29 12:52:16 -0400
Download Agent : com.google.Chrome
Type : Executable (x86-64)
Code-signed : Yes
Rule : Whitelisted (Unknown)
Signing Chain:
1. SHA-256 : ba1be5d2d60a43658a0c6ebf61b577e428439b53ef2e0b96ba90285e2c82a1b2
SHA-1 : 8fdbf6d6c22a97c472fb4961b7733ab0d8830ff7
Common Name : Developer ID Application: Kevin Wojniak
Organization : Kevin Wojniak
Organizational Unit : QK92QP33YN
Valid From : 2012/10/30 01:07:40 -0400
Valid Until : 2017/10/31 01:07:40 -0400
2. SHA-256 : 7afc9d01a62f03a2de9637936d4afe68090d2de18d03f29c88cfb0b1ba63587f
SHA-1 : 3b166c3b7dc4b751c9fe2afab9135641e388e186
Common Name : Developer ID Certification Authority
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2012/02/01 17:12:15 -0500
Valid Until : 2027/02/01 17:12:15 -0500
3. SHA-256 : b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024
SHA-1 : 611e5b662c593a08ff58d14ae22452d198df6c60
Common Name : Apple Root CA
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2006/04/25 17:40:36 -0400
Valid Until : 2035/02/09 16:40:36 -0500
```
Any of the desired information can be targeted with the `--key` flag
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key SHA-256
efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
```
Multiple `--key` flags are allowed
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key SHA-256 --key Rule
efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
Whitelisted (Unknown)
```
The `--json` flag can also be used at any point
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key SHA-256 --key Rule --json
{
"SHA-256" : "efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1",
"Rule" : "Whitelisted (Unknown)"
}
```
Multiple files are also supported as input
```sh
⇒ santactl fileinfo /bin/* --key SHA-256 --key Rule --json
[
{
"SHA-256" : "5d8e161c21fc1a43374c4cf21be05360dbe2ecea0165fd4725ae7a958f2a0b02",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "295fbc2356e8605e804f95cb6d6f992335e247dbf11767fe8781e2a7f889978a",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "9f9b36ec79b9fcaf649e17f2f94c544dd408c2ab630e73d7c62a7a43f1bc7b1d",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "08a09d2d9bade16872acdf5da1c4e9d29582ed985480a9e73fd389e98293c40d",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "48e4b938b363201ec11d06a13d8080c1bd77187d286780259b9304c96edc5324",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "7dff6291a29fdaf97dad64c0671dc5d1ecc42189bc5daf8ca08e2a3ae06aff95",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "7cbba457df4c02d6a7fb93046fea0e869732c65a2225bee6f2e8ec290d38c57b",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "39e894d1705656451f592884a56bcc76e7ffbb9ed2a8b81d5f2878e1c0e68dbe",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "8555ed4622410aa7b4379041acabf80fe452a90efe3be2697406935ff0d6822e",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "cee3e29089f8919ee904328904a7492995cfa398b027857fbf8b3e601397b308",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "da2cfa9fc2cabd41907f9d0931cea79000a19520fe0b3d73fc40537408730e40",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "73aee02c4761e5501b1fdfa51ccd316bf735017a5cc0a09d5bcc46f4e7112be9",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "3a1c4ca5a038b42b1fbfca6f9bec25d307a8af40afbe9c48b307372fe8167a2f",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "9dc8e1c5b6ec49602dd968eb88286e330220233f7cfa6e73fd37fc983a365084",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "78fd9b8749c2a216ca76ff4541754d4cf5a5e2e8c00710a85c3fdab171486f92",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "c4daaf12bd42adee60549872126e15186c75d89e760f078bfa6a45a861f6400f",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "9dba1cbb01bce47a9610a40cbcbc27704a754e31a889503eb0670c3a25f7ad72",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "a5ae86cd413589d9661fc604349fb153c0d6f5dfa3d9e95e01b8bc5e09bc1da1",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "a5ae86cd413589d9661fc604349fb153c0d6f5dfa3d9e95e01b8bc5e09bc1da1",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "c4c5517ff40a33006028853a19734d8cda8e2942cb9ba27b8310e07f18677487",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "a944b104742db59204b45f1dae657bd6a845ff2374e1ade3cf9f09cc428154cf",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "09e143cf3b6c4dcc98676cc45543613b83b6527b502d4dacb42b3f6c7036ef5a",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "47cea771e93aff464f1060a6a1a2c3855401e6cd22c3971b2b76fae92e8c33b4",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "5682f15628ae15e5c29aa37f19ec421bbe4aca47734864b6363b73a16f891888",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "83c29a2445d84daf51eebd51668753fb39600a136efc20aba7298a812b44974c",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "83929910d3cd2c401636337fadc747a9a8ea6c174bfd80f1e96b99d877ddfa6e",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "cccd818698aa802b116586a773643d0b951067dea8284304acaae62ac97b362b",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "2bf2d10a7529a88d340ce0255da52dbef9873ccb44e46d23af03abf70b8e54ca",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "956f2dc7ba31663dd3a9b70e84e6a2491980165426b90cacd10db4bd010c3353",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "da1a3ae959751b211928f175f6c8987408a976be44690022c92d45ef5a8cb6e5",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "1e51209ae4549a72432ad504341c0731a282b33ba99c5f7f4e2abc9993e09b0a",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "7dff6291a29fdaf97dad64c0671dc5d1ecc42189bc5daf8ca08e2a3ae06aff95",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "5d8e161c21fc1a43374c4cf21be05360dbe2ecea0165fd4725ae7a958f2a0b02",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "83929910d3cd2c401636337fadc747a9a8ea6c174bfd80f1e96b99d877ddfa6e",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "17372eafbe9e920d5715a9cffa59f881ef4ed949785c1e2adf9c067d550dbde6",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "b1834d55b76c65d57cef1219a30331452301e84b6e315f2a17e5b5b295ce1648",
"Rule" : "Whitelisted (Certificate)"
}
]
```
Recursive lookups of an application or directory is a soon to be added feature
```sh
⇒ santactl fileinfo --recursive /Applications/Santa.app --key SHA-256 --key Rule --key Type --json
[
{
"SHA-256" : "c149c10c83abaf6b602401106f098b68d47a1a433ab02455cef2ca8057cf4a82",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
},
{
"SHA-256" : "c339c3e5e04c732ae493dbc4a26d18fccc8bb48cea0cc0762ccd8754ef318a0b",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
},
{
"SHA-256" : "6ee757ab65d7c93e8b6a467b44cd2f0d10b6db7da8b6200e778c3ca279ea5619",
"Type" : "Executable (x86-64)",
"Rule" : "Whitelisted (Certificate)"
},
{
"SHA-256" : "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
},
{
"SHA-256" : "9814019f865a540d3635012a75db932eaefc9a62468750f2294350690430aadf",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
},
{
"SHA-256" : "05a9c9dbbf0a7a30f083e3dccd8db3d96845e0644930977b4e284c65083b89ac",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
},
{
"SHA-256" : "e1db8fdffc5017684f962c51fad059dcaa06ab5d551186aa85711f80b727d23d",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
}
]
```
##### rule
The rule command is covered in the [rules.md](rules.md) document.
##### sync
The sync command is covered in the [syncing.md](syncing.md) document.
##### Debug Commands
There are a few commands that are not included in the release versions of Santa. They are mainly used during development and only accessible with a debug build of Santa.
##### bundleinfo
This prints info about all of the executable Mach-O files within a bundle. It also prints the calculated bundle hash for that particular bundle. A bundle hash is a notion used by Santa to represent a set of binaries.
```sh
⇒ santactl bundleinfo /Applications/Hex\ Fiend.app
Hashing time: 12 ms
4 events found
BundleHash: 33da3e2d5e2ccbdb9d34fb9753c2c18805e6325853d2fb4eb947915c90113efc
BundleID: com.ridiculousfish.HexFiend
SHA-256: e592a7c65f803675c0b7d55ab7d2a1a2696c9f097a99dc28a4083d7387e53d95
Path: /Applications/Hex Fiend.app/Contents/Library/LaunchServices/com.ridiculousfish.HexFiend.PrivilegedHelper
BundleID: com.ridiculousfish.HexFiend
SHA-256: ce23d39a1a8ff2b42baad5a0204b24b57590bb7ff74c9552b3ba10d9c1517279
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate
BundleID: com.ridiculousfish.HexFiend
SHA-256: efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
Path: /Applications/Hex Fiend.app/Contents/MacOS/Hex Fiend
BundleID: com.ridiculousfish.HexFiend
SHA-256: 148d6ae55176b619e5eb9f5000922b3ca4c126206fc5782f925d112027f9db3c
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop
```
See the [santabs.md](santabs.md) document for more information on bundles and bundle hashes.
##### checkcache
This is used to check if a particular file is apart of santa-driver's kernel cache. Mainly for debugging purposes.
```sh
⇒ santactl checkcache /usr/bin/yes
File does not exist in cache
⇒ /usr/bin/yes
y
y
y
y
y
^C
⇒ santactl checkcache /usr/bin/yes
File exists in [whitelist] kernel cache
```
##### flushcache
This can be used to flush santa-driver's kernel cache, as shown here.
```sh
⇒ santactl checkcache /usr/bin/yes
File exists in [whitelist] kernel cache
⇒ sudo santactl flushcache
Cache flush requested
⇒ santactl checkcache /usr/bin/yes
File does not exist in cache
```

23
Docs/details/santad.md Normal file
View File

@@ -0,0 +1,23 @@
# santad
The santad process does the heavy lifting when it comes to making decisions about binary executions. It also handles brokering all of the XPC connections between the various components of Santa. It does all of this with performance being at the forefront.
##### A note on performance
On an idling machine, santad and the other components of Santa consume virtually no CPU and a minimal amount of memory (5-50MB). When lots of processes `execve()` at the same time, the CPU and memory usage can spike. All of the `execve()` decisions are made on high priority threads to ensure decisions are posted back to the kernel as soon as possible. A watchdog thread will log warnings when sustained high CPU (>20%) and memory (>250MB) usage by santad is detected.
##### On Launch
The very first thing santad does once it has been launched is to load and connect to santa-driver. Only one connection may be active at any given time.
At this point, santa-driver is loaded and running in the kernel, but is allowing all executions and not sending any messages to santad. Before santad tells santa-driver it is ready to receive messages, it needs to setup a few more things:
* The rule and event databases are initialized
* Connections to Santa (GUI) and santactl sync daemon are established.
* The config file is processed.
santad is now ready to start processing decision and logging messages from santa-driver. The listeners are started and santad sits in a run loop awaiting messages from santa-driver.
##### Running
Messages are read from a shared memory queue (`IODataQueueMemory` ) on a single thread. A callback is invoked for each message. The callback then dispatches all the work of processing a decision message to a concurrent high priority queue. The log messages are dispatched to a low priority queue for processing.

27
Docs/details/scopes.md Normal file
View File

@@ -0,0 +1,27 @@
# Scopes
In addition to rules, Santa can whitelist or blacklist based on scopes. Currently, only a few scopes are implemented. They fall into one of two categories: a whitelist scope or blacklist scope. Scopes are evaluated after rules, with blacklist evaluation preceding whitelist.
Scopes are a broader way of whitelisting or blacklisting `execve()`s.
For configuration of scopes see [configuration.md](../deployment/configuration.md).
##### Blacklist Scopes
| Scope | Configurable |
| -------------------- | ------------ |
| Blacklist Path Regex | Yes |
| Missing __PAGEZERO | Yes |
##### Whitelist Scopes
| Scope | Configurable |
| -------------------- | ------------ |
| Whitelist Path Regex | Yes |
| Not a Mach-O | No |
As seen above, Santa will whitelist any non Mach-O binary under a whitelist scope. However, a blacklist regex or binary SHA-256 rule can be used to block non Mach-O `execve()`s since they are evaluated before the whitelist scopes.
##### Regex Caveats
The paths covered by the whitelist and blacklist regex patterns are not tracked. If an `execve()` is allowed initially, then moved into a blacklist directory, Santa has no knowledge of that move. Since santa-driver caches decisions, the recently moved file will continue to be allowed to `execve()` even though it is now within a blacklisted regex path. The cache holds "allow" decisions until invalidated and "deny" decisions for 500 milliseconds. Going from a blacklist path to a whitelist path is not largely affected.

View File

@@ -0,0 +1,108 @@
# Building
Santa makes use of [rake](https://ruby.github.io/rake/) for building and testing Santa. All of the [releases](https://github.com/google/santa/releases) are made using this same process. Santa's releases are codesigned with Google's KEXT signing certificate. This allows Santa to be loaded with SIP fully enabled.
#### Cloning
Clone the source and change into the directory.
```sh
git clone https://github.com/google/santa
cd santa
```
The above command will default to using the `master` branch. If you wanted to build, run or test a specific version of Santa use this command.
```sh
git checkout <version, i.e. 0.9.19>
```
#### Building
Build a debug version of Santa. This keeps all the debug symbols, adds additional logs and does not optimize the compiled output. For speed sensitive tests make sure to benchmark a release version too.
```sh
rake build:debug
```
Build a release version of Santa.
```sh
rake build:release
```
Both of these just output the binaries that makeup Santa in the default Xcode build location. To actually run what was built, see the next section.
#### Running
On macOS 10.11+ System Integrity Protection (SIP) prevents loading of kernel extensions that are not signed by an Apple KEXT signing certificate. To be able to load and test a non-release version of Santa, SIP will have to be configured to allow non-Apple KEXT signing certificates.
__This is only to be done a machine that is actively developing, unloading and loading kernel extensions.__
1. Boot into Recovery Mode: Reboot and hold down `command+r`
2. From the utilities menu select `Terminal`
3. Disable the KEXT feature of SIP: `csrutil enable --without kext`
4. Reboot
You should now be able to load and run a non-release version of Santa.
Build and run a debug version of Santa.
```sh
rake reload:debug
```
Build and run a release version of Santa.
```sh
rake reload:release
```
#### Debugging
Xcode and lldb can be used to debug Santa, just like any other project. Instead of clicking the play button to launch and attach to a process, you can attach to an already running, or soon to by running, component of Santa. To do this select the Debug menu and choose `Attach to Process by PID or Name… `. Below are the four components of Santa and who to debug the process as.
Note: santa-driver (the kernel extension) cannot be debugged by attaching with Xcode.
Note: Xcode can attach to santad without interruption, however any breakpoints in the decision making codepath can deadlock the machine. Using lldb directly to attach to santad will deadlock the machine.
| process | user |
| -------- | ---- |
| santad | root |
| Santa* | me |
| santactl | me |
| santabs | root |
Xcode will then wait for the process to start. Issue this command to restart all the Santa processes in debug mode.
*The Santa (GUI) process is the only component of Santa that can be launched and debugged from Xcode directly. All the other components are launched with privileges and/or are scoped to an XPC service that launchd scopes to a hosting bundle. Thus the need for the `Attach to Process by PID or Name…` technique. See the [ipc](../details/ipc.md) document for for details.
```sh
rake reload:debug
```
Now the process is attached in Xcode and you can debug your day away.
#### Tests
Run all the logic / unit tests
```sh
rake tests:logic
```
Run all of santa-driver kernel extension tests
```sh
rake tests:kernel
```
#### Releases
Creates a release build of Santa with a version based of the newest tag. Also saves the dsym files for each component of Santa. This makes debugging and interpreting future crashes or kernel panics much easier.
```sh
rake dist
```

46
Docs/index.md Normal file
View File

@@ -0,0 +1,46 @@
# Welcome to the Santa Docs
Santa is a binary whitelisting / blacklisting system for macOS. Here you will find the documentation for understanding how Santa works, how to deploy it and how to contribute.
#### Introduction
The following documents give an overview of how Santa accomplishes binary whitelisting / blacklisting at the enterprise scale.
- [Binary Whitelisting](introduction/binary-whitelisting-overview.md): How Santa makes allow or deny decisions for any `execve()` taking place.
- [Syncing](introduction/syncing-overview.md): How configuration and whitelist / blacklist rules are applied from a sync server.
#### Deployment
* [Configuration](deployment/configuration.md): The local and sync server configuration options.
#### Development
* [Building Santa](development/building.md): How to build and load Santa for testing on a development machine.
* [Contributing](../CONTRIBUTING.md): How to contribute a bug fix or new feature to Santa.
#### Details
For those who want even more details on how Santa works under the hood, this section is for you.
###### Binaries
There are five main components that make up Santa whose core functionality is described in snippets below. For additional detail on each component, visit their respective pages. These quick descriptions do not encompass all the jobs performed by each component, but do provide a quick look at the basic functionality utilized to achieve the goal of binary whitelisting / blacklisting.
* [santa-driver](details/santa-driver.md): A macOS kernel extension that participates in `execve()` decisions.
* [santad](details/santad.md): A user-land root daemon that makes decisions on behalf of santa-driver requests.
* [santactl](details/santactl.md): A user-land anonymous daemon that communicates with a sync server for configurations and policies. santactl can also be used by a user to manually configure Santa when using the local configuration.
* [santa-gui](details/santa-gui.md): A user-land GUI daemon that displays notifications when an `execve()` is blocked.
* [santabs](details/santabs.md): A user-land root daemon that finds Mach-O binaries within a bundle and creates events for them.
###### Concepts
Additional documentation on the concepts that support the operation of the main components:
* [mode](details/mode.md): An operating mode, either Monitor or Lockdown.
* [events](details/events.md): Represents an `execve()` that was blocked, or would have been blocked, depending on the mode.
* [rules](details/rules.md): Represents allow or deny decisions for a given `execve()`. Can either be a binary's SHA-256 hash or a leaf code-signing certificate's SHA-256 hash.
* [scopes](details/scopes.md): The level at which an `execve()` was allowed or denied from taking place.
* [syncing](introduction/syncing-overview.md): How Santa communicates with a TLS server for configuration, rules and event uploading.
* [ipc](details/ipc.md): How all the components of Santa communicate.
duction/syncing-overview.
* [logs](details/logs.md): What and where Santa logs.

View File

@@ -0,0 +1,31 @@
# Binary Whitelisting Overview
#### Background
The decision flow starts in the kernel. The macOS kernel is extensible by way of a kernel extension (KEXT). macOS makes available kernel programming interfaces (KPIs) to be used by a KEXT. Santa utilizes the Kernel Authorization (Kauth) KPI. This is a very powerful and verbose interface that gives Santa the ability to listen in on most vnode and file systems operations and to take actions, directly or indirectly, on the operations being performed. Still, there are some limitations to Kauth which are pointed out in the santa-driver document. For more information on the santa-driver KEXT see the [santa-driver.md](../details/santa-driver.md) document.
#### Flow of an execve()
This is a high level overview of the binary whitelisting / blacklisting decision process. For a more detailed account of each part, see the respective documentation. This flow does not cover the logging component of Santa, see the [logs.md](../details/logs.md) documentation for more info.
###### Kernel Space
0. santa-driver registers itself as a `KAUTH_SCOPE_VNODE` listener. This flow follows how santa-driver handles `KAUTH_VNODE_EXECUTE` events.
1. A santa-driver Kauth callback function is executed by the kernel when a process is trying to `execve()`. In most cases, the `execve()` takes place right after a process calls `fork()` to start a new process. This function is running on a kernel thread representing the new process. Information on where to find the executable is provided. This information is known as the `vnode_id`.
2. santa-driver then checks if its cache has an allow or deny entry for the `vnode_id`. If so it returns that decision to the Kauth KPI.
* If Kauth receives a deny, it will stop the `execve()` from taking place.
* If Kauth receives an allow, it will defer the decision. If there are other Kauth listeners, they also have a chance deny or defer.
3. If there is no entry for the `vnode_id` in the cache a few actions occur:
* santa-driver hands off the decision making to santad.
* A new entry is created in the cache for the `vnode_id` with a special value of `ACTION_REQUEST_BINARY`. This is used as a placeholder until the decision from santad comes back. If another process tries to `execve()` the same `vnode_id`, santa-driver will have that thread wait for the in-flight decision from santad. All subsequent `execve()`s for the same `vnode_id` will use the decision in the cache as explained in #2, until the cache is invalidated. See the [santa-driver.md](../details/santa-driver.md) document for more details on the cache invalidation.
* If the executing file is written to while any of the threads are waiting for a response the `ACTION_REQUEST_BINARY` entry is removed, forcing the decision-making process to be restarted.
###### User Space
1. santad is listening for decision requests from santa-driver.
* More information is collected about the executable that lives at the `vnode_id`. Since this codepath has a sleeping kernel thread waiting for a decision, extra care is taken to be as performant as possible.
2. santad uses the information it has gathered to make a decision to allow or deny the `execve()`. There are more details on how these decisions are made in the [rules.md](../details/rules.md) and [scopes.md](../details/scopes.md) documents.
3. The decision is posted back to santa-driver.
4. If there was a deny decision, a message is sent to Santa GUI to display a user popup notification.

View File

@@ -0,0 +1,27 @@
# Syncing Overview
#### Background
Santa can be run and configured without a sync server. Doing so will enable an admin to configure rules with the `santactl rule` command. Using a sync server will enable an admin to configures rules and multiple other settings from the sync server itself. Santa was designed from the start with a sync server in mind. This allows an admin to easily configure and sync rules across a fleet of macOS systems. This document explains the syncing process.
#### Flow of a full sync
This is a high level overview of the syncing process. For a more a more detailed account of each part, see the respective documentation. The santaclt binary can be run in one of two modes, daemon and non-daemon. The non-daemon mode does one full sync and exits. This is the typical way a user will interact with Santa, mainly to force a full sync. The daemon mode is used by santad to schedule full syncs, listen for push notifications and upload events.
0. When the santad process starts up, it looks for a `SyncBaseURL` key/value in the config. If one exists it will `fork()` and `execve()` `santactl sync —-daemon`. Before the new process calls `execve()`, all privileges are dropped. All privileged actions are then restricted to the XPC interface made available to santactl by santad. Since this santactl process is running as a daemon it too exports an XPC interface so santad can interact with the process efficiently and securely. To ensure syncing reliability santad will restart the santactl daemon if it is killed or crashes.
1. The santactl daemon process now schedules a full sync for 15 sec in the future. The 15 sec is used to let santad settle before santactl starts sending rules from the sync server to process.
2. The full sync starts. There are a number of stages to a full sync:
1. preflight: The sync server can set various settings for Santa.
2. logupload (optional): The sync server can request that the Santa logs be uploaded to an endpoint.
3. eventupload (optional): If Santa has generated events, it will upload them to the sync-server.
4. ruledownload: Download rules from the sync server.
5. postflight: Updates timestamps for successful syncs.
3. After the full sync completes a new full sync will be scheduled, by default this will be 10min. However there are a few ways to manipulate this:
1. The sync server can send down a configuration in the preflight to override the 10min interval. It can be anything greater than 10min.
2. Firebase Cloud Messaging (FCM) can be used. The sync server can send down a configuration in the preflight to have the santactl daemon to start listening for FCM messages. If a connection to FCM is made, the full sync interval drops to a default of 4 hours. This can be further configured by a preflight configuration. The FCM connection allows the sync-sever to talk directly with Santa. This way we can reduce polling the sync server dramatically.
4. Full syncs will continue to take place at their configured interval. If configured FCM messages will continue to be digested and acted upon.
#### santactl XPC interface
When running as a daemon, the santactl process makes available an XPC interface for use by santad. This allows santad to send blocked binary or bundle events directly to santactl for immediate upload to the sync-server, enabling a smoother user experience. The binary that was blocked on macOS is immediately available for viewing or handling on the sync-server.

3
Docs/theme/Santa.css Normal file
View File

@@ -0,0 +1,3 @@
.wy-side-nav-search {
background-color: rgb(253, 67, 69);
}

25
Fuzzing/CMakeLists.txt Normal file
View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.10.0)
set(LIBFUZZER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libFuzzer/bin/libFuzzer.a")
function(ImportLibFuzzer)
add_custom_command(
OUTPUT "${LIBFUZZER_PATH}"
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/libFuzzer/build.sh"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/libFuzzer/build.sh"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libFuzzer"
COMMENT "Building libFuzzer..."
)
add_custom_target(libfuzzer_builder DEPENDS "${LIBFUZZER_PATH}")
endfunction()
function(main)
ImportLibFuzzer()
add_subdirectory(santacache)
add_subdirectory(santad)
add_subdirectory(santactl)
endfunction()
main()

4
Fuzzing/libFuzzer/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
bin
llvm-*.src
llvm-*.src.tar.xz

109
Fuzzing/libFuzzer/build.sh Executable file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env bash
LLVM_VERSION='5.0.1'
LLVM_COMPILERRT_TARBALL_NAME="llvm-${LLVM_VERSION}.src.tar.xz"
LLVM_COMPILERRT_SRC_FOLDER_NAME=`echo "${LLVM_COMPILERRT_TARBALL_NAME}" | cut -d '.' -f 1-4`
LLVM_COMPILERRT_TARBALL_URL="http://releases.llvm.org/${LLVM_VERSION}/${LLVM_COMPILERRT_TARBALL_NAME}"
LIBFUZZER_FOLDER="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LOG_FILE=`mktemp`
main() {
echo "libFuzzer build script"
echo " > Checking dependencies..."
checkDependencies || return 1
echo " > Entering libFuzzer folder..."
cd "${LIBFUZZER_FOLDER}" > /dev/null 2>&1
if [ $? -ne 0 ] ; then
echo "Failed to enter the libFuzzer folder: ${LIBFUZZER_FOLDER}"
return 1
fi
if [ ! -f "${LLVM_COMPILERRT_TARBALL_NAME}" ] ; then
echo " > Downloading the LLVM tarball..."
curl "${LLVM_COMPILERRT_TARBALL_URL}" -o "${LLVM_COMPILERRT_TARBALL_NAME}" > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
dumpLogFile "Failed to download the LLVM tarball"
return 1
fi
else
echo " > An existing LLVM tarball was found"
fi
if [ -d "${LLVM_COMPILERRT_SRC_FOLDER_NAME}" ] ; then
echo " > Deleting existing LLVM folder..."
rm -rf "${LLVM_COMPILERRT_SRC_FOLDER_NAME}" > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
dumpLogFile "Failed to delete the existing source folder"
return 1
fi
fi
echo " > Extracting the LLVM tarball..."
tar xf "${LLVM_COMPILERRT_TARBALL_NAME}" > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
rm "${LLVM_COMPILERRT_TARBALL_NAME}" "${LLVM_COMPILERRT_SRC_FOLDER_NAME}"
dumpLogFile "Failed to extract the LLVM tarball"
return 1
fi
if [ -d "bin" ] ; then
echo " > Deleting existing bin folder..."
rm -rf "bin" > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
dumpLogFile "Failed to delete the existing bin folder"
return 1
fi
fi
mkdir "bin" > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
dumpLogFile "Failed to create the bin folder"
return 1
fi
echo " > Building libFuzzer..."
( cd "bin" && "../${LLVM_COMPILERRT_SRC_FOLDER_NAME}/lib/Fuzzer/build.sh" ) > "${LOG_FILE}" 2>&1
if [ $? -ne 0 ] ; then
dumpLogFile "Failed to build the library"
return 1
fi
printf "\nFinished building libFuzzer\n"
rm "${LOG_FILE}"
return 0
}
checkDependencies() {
executable_list=( "clang++" "curl" "tar" )
for executable in "${executable_list[@]}" ; do
which "${executable}" > /dev/null 2>&1
if [ $? -ne 0 ] ; then
echo "The following program was not found: ${executable}"
return 1
fi
done
return 0
}
dumpLogFile() {
if [ $# -eq 1 ] ; then
local message="$1"
else
local message="An error has occurred"
fi
printf "${message}\n"
printf "Log file follows\n===\n"
cat "${LOG_FILE}"
printf "\n===\n"
rm "${LOG_FILE}"
}
main $@
exit $?

3
Fuzzing/santacache/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
santacache.dSYM
santacache

View File

@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.10.0)
project(santacache_fuzzer)
set(CMAKE_CXX_STANDARD 11)
function(main)
set(PROJECT_SOURCEFILES
src/main.cpp
)
add_executable("${PROJECT_NAME}" EXCLUDE_FROM_ALL ${PROJECT_SOURCEFILES})
add_dependencies("${PROJECT_NAME}" libfuzzer_builder)
target_link_libraries("${PROJECT_NAME}" PRIVATE "${LIBFUZZER_PATH}")
target_include_directories("${PROJECT_NAME}" PRIVATE
"${CMAKE_SOURCE_DIR}/Source/common"
"${CMAKE_SOURCE_DIR}/Source/santa-driver"
)
target_compile_options("${PROJECT_NAME}" PRIVATE
-g -O0 -Wno-deprecated-declarations
-fsanitize-coverage=trace-pc-guard
-mmacosx-version-min=${MACOSX_VERSION_MIN}
)
target_link_libraries("${PROJECT_NAME}" PRIVATE
-fsanitize=address -fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
)
AddFuzzTarget("${PROJECT_NAME}" 16 60 false)
endfunction()
main()

Binary file not shown.

View File

@@ -0,0 +1,41 @@
/// 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.
#include <SantaCache.h>
#include <iostream>
#include <cstdint>
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
static SantaCache<uint64_t, uint64_t> decision_cache(5000, 2);
std::uint64_t fields[2] = {};
if (size > 16) {
std::cout << "Invalid size! Start with -max_len=16\n";
return 1;
}
std::memcpy(fields, data, size);
decision_cache.set(fields[0], fields[1]);
auto returned_value = decision_cache.get(fields[0]);
if (returned_value != fields[1]) {
std::cout << fields[0] << ", " << fields[1] << " -> " << returned_value << "\n";
return 1;
}
return 0;
}

View File

@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.10.0)
project(santactl_fuzzer)
set(CMAKE_CXX_STANDARD 11)
function(main)
set(PROJECT_SOURCEFILES
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncRuleDownload.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncConstants.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncStage.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncState.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTRule.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTLogging.m"
src/main.mm
)
add_executable("${PROJECT_NAME}" EXCLUDE_FROM_ALL ${PROJECT_SOURCEFILES})
target_compile_options("${PROJECT_NAME}" PRIVATE
-fobjc-arc -Wno-everything -fmodules -fcxx-modules
-mmacosx-version-min=${MACOSX_VERSION_MIN}
)
target_compile_definitions("${PROJECT_NAME}" PRIVATE
COCOAPODS=1
)
target_include_directories("${PROJECT_NAME}" PRIVATE
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync"
"${CMAKE_SOURCE_DIR}/Source/common"
"${CMAKE_SOURCE_DIR}/Source/santad"
)
target_link_libraries("${PROJECT_NAME}" PRIVATE
MOLCertificate MOLCodesignChecker
MOLAuthenticatingURLSession FMDB MOLFCMClient
)
#
# Add libfuzzer
#
add_dependencies("${PROJECT_NAME}" libfuzzer_builder)
target_link_libraries("${PROJECT_NAME}" PRIVATE "${LIBFUZZER_PATH}")
target_compile_options("${PROJECT_NAME}" PRIVATE
-g -O0 -Wno-deprecated-declarations
-fsanitize-coverage=trace-pc-guard
)
target_link_libraries("${PROJECT_NAME}" PRIVATE
-fsanitize=address -fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
)
AddFuzzTarget("${PROJECT_NAME}" 428 60 false)
endfunction()
main()

View File

@@ -0,0 +1,16 @@
{
"rules": [
{
"rule_type": "BINARY",
"policy": "BLACKLIST",
"sha256": "2dc104631939b4bdf5d6bccab76e166e37fe5e1605340cf68dab919df58b8eda",
"custom_msg": "blacklist firefox"
},
{
"rule_type": "CERTIFICATE",
"policy": "BLACKLIST",
"sha256": "e7726cf87cba9e25139465df5bd1557c8a8feed5c7dd338342d8da0959b63c8d",
"custom_msg": "blacklist dash app certificate"
}
]
}

View File

@@ -0,0 +1,62 @@
/// 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.
#include <iostream>
#include <cstdint>
#include <vector>
#include <SNTCommandSyncRuleDownload.h>
#include <SNTCommandSyncState.h>
#include <SNTCommandSyncConstants.h>
#include <SNTRule.h>
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
NSData *buffer = [NSData dataWithBytes:static_cast<const void *>(data) length:size];
if (!buffer) {
return 0;
}
NSError *error;
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:buffer options:0 error:&error];
if (!response) {
return 0;
}
if (![response isKindOfClass:[NSDictionary class]]) {
return 0;
}
if (![response objectForKey:kRules]) {
return 0;
}
SNTCommandSyncState *state = [[SNTCommandSyncState alloc] init];
if (!state) {
return 0;
}
SNTCommandSyncRuleDownload *obj = [[SNTCommandSyncRuleDownload alloc] initWithState:state];
if (!obj) {
return 0;
}
for (NSDictionary *ruleDict in response[kRules]) {
SNTRule *rule = [obj ruleFromDictionary:ruleDict];
if (rule) {
std::cerr << "Rule: " << [[rule description] UTF8String] << "\n";
}
}
return 0;
}

View File

@@ -0,0 +1,109 @@
cmake_minimum_required(VERSION 3.10.0)
project(santad_fuzzer)
set(CMAKE_CXX_STANDARD 11)
function(main)
GenerateFuzzTarget(src/databaseRuleAddRules.mm 45 60 true)
GenerateFuzzTarget(src/checkCacheForVnodeID.mm 16 60 true)
GenerateFuzzTarget(src/databaseRemoveEventsWithIDs.mm 80 60 true)
endfunction()
function(GenerateFuzzTarget source_file data_size timeout run_as_root)
# Generate one new project for each source file in the 'src' folder. Copy
# the project source files and settings from santactl
set(PROJECT_SANTACTLSOURCEFILES
"${CMAKE_SOURCE_DIR}/Source/santactl/SNTCommand.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/SNTCommand.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/SNTCommandController.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/SNTCommandController.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Resources/santactl-Info.plist"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandBundleInfo.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandCheckCache.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandFileInfo.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandFlushCache.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandRule.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandStatus.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/SNTCommandVersion.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/NSData+Zlib.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/NSData+Zlib.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSync.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncConstants.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncConstants.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncEventUpload.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncEventUpload.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncLogUpload.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncLogUpload.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncManager.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncManager.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncPostflight.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncPostflight.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncPreflight.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncPreflight.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncRuleDownload.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncRuleDownload.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncStage.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncStage.m"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncState.h"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync/SNTCommandSyncState.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTConfigurator.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTFileInfo.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTRule.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTStoredEvent.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTSystemInfo.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCControlInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCSyncdInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTLogging.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTDropRootPrivs.m"
)
get_filename_component(target_name "${source_file}" NAME_WE)
set(target_name "santad_${target_name}_fuzzer")
add_executable("${target_name}" EXCLUDE_FROM_ALL ${source_file} ${PROJECT_SANTACTLSOURCEFILES})
target_compile_options("${target_name}" PRIVATE
-fobjc-arc -Wno-everything -fmodules -fcxx-modules
-mmacosx-version-min=${MACOSX_VERSION_MIN}
)
target_compile_definitions("${target_name}" PRIVATE
COCOAPODS=1
)
target_include_directories("${target_name}" PRIVATE
"${CMAKE_SOURCE_DIR}/Source/santactl"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands"
"${CMAKE_SOURCE_DIR}/Source/santactl/Commands/sync"
"${CMAKE_SOURCE_DIR}/Source/santad"
"${CMAKE_SOURCE_DIR}/Source/common"
)
target_link_libraries("${target_name}" PRIVATE
MOLCertificate MOLCodesignChecker
MOLAuthenticatingURLSession FMDB MOLFCMClient
MOLXPCConnection
)
#
# Add libfuzzer
#
add_dependencies("${target_name}" libfuzzer_builder)
target_link_libraries("${target_name}" PRIVATE "${LIBFUZZER_PATH}")
target_compile_options("${target_name}" PRIVATE
-g -O0 -Wno-deprecated-declarations
-fsanitize-coverage=trace-pc-guard
)
target_link_libraries("${target_name}" PRIVATE
-fsanitize=address -fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
)
AddFuzzTarget("${target_name}" ${data_size} ${timeout} ${run_as_root})
endfunction()
main()

View File

@@ -0,0 +1 @@
К'.p▒└G╗М┐║ЙSЮ╝и▌РУерЭxt1iАЫШ9ы*H╩4R"═©$-├Уww╙+Р╝╘[┼иу╧oС┬ОwRpЗя≤х°е

View File

@@ -0,0 +1,55 @@
/// 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.
#include <iostream>
#include <cstdint>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandController.h"
#import "SNTRule.h"
#import "SNTXPCControlInterface.h"
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
if (size > 16) {
std::cerr << "Invalid buffer size of " << size
<< " (should be <= 16)" << std::endl;
return 1;
}
santa_vnode_id_t vnodeID = {};
std::memcpy(&vnodeID, data, size);
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
daemonConn.invalidationHandler = ^{
printf("An error occurred communicating with the daemon, is it running?\n");
exit(1);
};
[daemonConn resume];
[[daemonConn remoteObjectProxy] checkCacheForVnodeID:vnodeID
withReply:^(santa_action_t action) {
if (action == ACTION_RESPOND_ALLOW) {
std::cerr << "File exists in [whitelist] kernel cache" << std::endl;;
} else if (action == ACTION_RESPOND_DENY) {
std::cerr << "File exists in [blacklist] kernel cache" << std::endl;;
} else if (action == ACTION_UNSET) {
std::cerr << "File does not exist in cache" << std::endl;;
}
}];
return 0;
}

View File

@@ -0,0 +1,51 @@
/// 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.
#include <iostream>
#include <cstdint>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandController.h"
#import "SNTRule.h"
#import "SNTXPCControlInterface.h"
#pragma pack(push, 1)
#pragma pack(pop)
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
auto *eventId = reinterpret_cast<const std::uint64_t *>(data);
std::size_t eventIdCount = size / sizeof(std::uint64_t);
if (eventIdCount == 0) {
return 0;
}
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
daemonConn.invalidationHandler = ^{
printf("An error occurred communicating with the daemon, is it running?\n");
exit(1);
};
[daemonConn resume];
NSMutableSet *eventIds = [NSMutableSet setWithCapacity:eventIdCount];
for (std::size_t i = 0; i < eventIdCount; i++) {
auto id = [NSNumber numberWithInteger:eventId[i]];
[eventIds addObject:id];
}
[[daemonConn remoteObjectProxy] databaseRemoveEventsWithIDs:[eventIds allObjects]];
return 0;
}

View File

@@ -0,0 +1,73 @@
/// 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.
#include <iostream>
#include <cstdint>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "SNTCommandController.h"
#import "SNTRule.h"
#import "SNTXPCControlInterface.h"
#pragma pack(push, 1)
struct InputData {
std::uint32_t cleanSlate;
std::uint32_t state;
std::uint32_t type;
char hash[33];
};
#pragma pack(pop)
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
if (size > sizeof(InputData)) {
std::cerr << "Invalid buffer size of " << size
<< " (should be <= " << sizeof(InputData)
<< ")" << std::endl;
return 1;
}
InputData input_data = {};
std::memcpy(&input_data, data, size);
SNTRule *newRule = [[SNTRule alloc] init];
newRule.state = (SNTRuleState) input_data.state;
newRule.type = (SNTRuleType) input_data.type;
newRule.shasum = @(input_data.hash);
newRule.customMsg = @"";
MOLXPCConnection *daemonConn = [SNTXPCControlInterface configuredConnection];
daemonConn.invalidationHandler = ^{
printf("An error occurred communicating with the daemon, is it running?\n");
exit(1);
};
[daemonConn resume];
[[daemonConn remoteObjectProxy] databaseRuleAddRules:@[newRule]
cleanSlate:NO
reply:^(NSError *error) {
if (!error) {
if (newRule.state == SNTRuleStateRemove) {
printf("Removed rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
} else {
printf("Added rule for SHA-256: %s.\n", [newRule.shasum UTF8String]);
}
}
}];
return 0;
}

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.9)
- MOLCodesignChecker (1.10):
- MOLCertificate (~> 1.8)
- MOLFCMClient (1.7):
- MOLAuthenticatingURLSession (~> 2.4)
- MOLXPCConnection (1.2):
- 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: e9e88a396c57032cab847f51a46e20c730cd752a
MOLCodesignChecker: b0d5db9d2f9bd94e0fd093891a5d40e5ad77cbc0
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
MOLXPCConnection: c27af5cb1c43b18319698b0e568a8ddc2fc1e306
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
PODFILE CHECKSUM: acd378b3727c923d912e09812da344f7375c14fe
PODFILE CHECKSUM: ddca043a7ace9ec600c108621c56d13a50d17236
COCOAPODS: 1.2.1
COCOAPODS: 1.5.3

View File

@@ -1,4 +1,6 @@
Santa [![Build Status](https://travis-ci.org/google/santa.png?branch=master)](https://travis-ci.org/google/santa)
Santa
[![Build Status](https://travis-ci.org/google/santa.png?branch=master)](https://travis-ci.org/google/santa)
[![Documentation Status](https://readthedocs.org/projects/santa/badge/?version=latest)](https://santa.readthedocs.io/en/latest/?badge=latest)
=====
<p align="center">
@@ -13,31 +15,35 @@ 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.
Santa is a project of Google's Macintosh Operations Team.
Docs
========
The Santa docs are stored in the [Docs](https://github.com/google/santa/blob/master/Docs) directory. A Read the Docs instance is available here: https://santa.readthedocs.io.
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.
@@ -48,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
@@ -56,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.
@@ -78,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
@@ -93,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,
@@ -119,10 +124,8 @@ A tool like Santa doesn't really lend itself to screenshots, so here's a video i
<img src="https://zippy.gfycat.com/MadFatalAmphiuma.gif" alt="Santa Block Video" />
</p>
Building
Building with Xcode
========
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
@@ -139,6 +142,29 @@ rake build:debug
Note: the Xcode project is setup to use any installed "Mac Developer" certificate
and for security-reasons parts of Santa will not operate properly if not signed.
For more details on building see the [building.md](https://github.com/google/santa/blob/master/Docs/development/building.md) document.
Building with CMake
========
### General steps
1. Install Xcode and the command line tools
2. Install CMake using homebrew
3. Clone the santa source code repository
4. Set the signing key
5. Create a build folder and configure the project
6. Run make
Example
git clone https://github.com/google/santa.git
mkdir build
cd build
export CODESIGN_IDENTITY=XXX
cmake ../santa
make -j `sysctl -n hw.ncpu`
The CODESIGN_IDENTITY parameter can also be passed directly to CMake: cmake -DCODESIGN_IDENTITY=XXX /path/to/source/code
Kext Signing
============
Kernel extensions on macOS 10.9 and later must be signed using an Apple-provided

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,15 +142,13 @@
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 */; };
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 409232791A51B65D00A04527 /* SNTCommandRule.m */; };
59D56CF2D9C5BD9B7E3CC56D /* libPods-santad-santabs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14B98F4051188ECB7D024331 /* libPods-santad-santabs.a */; };
81133DB01F3A76F700917FF9 /* SNTCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 81133DAF1F3A75CE00917FF9 /* SNTCommand.m */; };
81133DB11F3A77C600917FF9 /* SNTCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 81133DAF1F3A75CE00917FF9 /* SNTCommand.m */; };
B352A545B76783D568A6D0C5 /* libPods-Santa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 90E9D568200AB9B642E06272 /* libPods-Santa.a */; };
C714F8B11D8044D400700EDF /* SNTCommandFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD5FBE1909D64A006B445C /* SNTCommandFileInfo.m */; };
C714F8B21D8044FE00700EDF /* SNTCommandController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */; };
@@ -166,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 */; };
@@ -177,16 +175,21 @@
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 */; };
D1761D2DAE8C790F29AFE6C9 /* libPods-LogicTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D949AA996AEAC326A4F6596 /* libPods-LogicTests.a */; };
D221001320AB35FB003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */; };
D221001420AB3609003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */; };
D221001520AB360A003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */; };
D221001620AB360A003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */; };
D221001720AB360B003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */; };
D6D356C5BC8709C2E355C113 /* libPods-santactl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E3B4B2438711ACD7D560014 /* libPods-santactl.a */; };
/* End PBXBuildFile section */
@@ -289,6 +292,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>"; };
@@ -326,7 +330,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>"; };
@@ -343,14 +346,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>"; };
@@ -413,9 +412,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; };
@@ -427,11 +423,19 @@
670AD2EB5E3572321B058D02 /* Pods-Santa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.debug.xcconfig"; sourceTree = "<group>"; };
6C489E087A247B24480DB954 /* Pods-LogicTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LogicTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests.debug.xcconfig"; sourceTree = "<group>"; };
7D949AA996AEAC326A4F6596 /* libPods-LogicTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LogicTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81133DAE1F3A75CE00917FF9 /* SNTCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommand.h; sourceTree = "<group>"; };
81133DAF1F3A75CE00917FF9 /* SNTCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommand.m; sourceTree = "<group>"; };
8EF10E4B8C86CED022C72F1B /* Pods-santactl.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santactl.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santactl/Pods-santactl.debug.xcconfig"; sourceTree = "<group>"; };
90E9D568200AB9B642E06272 /* libPods-Santa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Santa.a"; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
@@ -446,10 +450,13 @@
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>"; };
C7FB56FF1DBFC213004E14EF /* SNTSyncdQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTSyncdQueue.m; sourceTree = "<group>"; };
D221000F20AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCUnprivilegedControlInterface.h; sourceTree = "<group>"; };
D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTXPCUnprivilegedControlInterface.m; sourceTree = "<group>"; };
D7DEE68F05C49966396A2F10 /* Pods-santad-santabs.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad-santabs.release.xcconfig"; path = "Pods/Target Support Files/Pods-santad-santabs/Pods-santad-santabs.release.xcconfig"; sourceTree = "<group>"; };
D9B2D7095028D87E12E63EF7 /* Pods-santad-santabs.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad-santabs.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santad-santabs/Pods-santad-santabs.debug.xcconfig"; sourceTree = "<group>"; };
DF5FE88E12AB307864A53CE7 /* Pods-santactl.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santactl.release.xcconfig"; path = "Pods/Target Support Files/Pods-santactl/Pods-santactl.release.xcconfig"; sourceTree = "<group>"; };
@@ -535,9 +542,7 @@
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */,
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
);
path = LogicTests;
sourceTree = "<group>";
@@ -545,6 +550,7 @@
0D260DB018B68E12002A0B55 /* Resources */ = {
isa = PBXGroup;
children = (
C7EAF71720A0A20B00745126 /* DirectoryBundle */,
C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */,
0D536ED51B8E7A2E0039A26D /* bad_pagezero */,
0D2CD4601A81C7B100C9C910 /* dn.plist */,
@@ -563,6 +569,8 @@
0D35BDA018FD71CE00921A21 /* santactl */ = {
isa = PBXGroup;
children = (
81133DAE1F3A75CE00917FF9 /* SNTCommand.h */,
81133DAF1F3A75CE00917FF9 /* SNTCommand.m */,
0D35BDAA18FD7CFD00921A21 /* SNTCommandController.h */,
0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */,
0D35BDA118FD71CE00921A21 /* main.m */,
@@ -726,8 +734,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 */,
@@ -740,14 +746,14 @@
0D42D2B419D1D98A00955F08 /* SNTSystemInfo.m */,
C7C721AF1E23FF300051FAA6 /* SNTXPCBundleServiceInterface.h */,
C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */,
0D6FDC9418C93A020044685C /* SNTXPCConnection.h */,
0D6FDC9518C93A020044685C /* SNTXPCConnection.m */,
0DCD605319115D17006B445C /* SNTXPCControlInterface.h */,
0DCD605419115D17006B445C /* SNTXPCControlInterface.m */,
0DC8C9E3180CC3BC00FCFB29 /* SNTXPCNotifierInterface.h */,
0DCD604E19115A06006B445C /* SNTXPCNotifierInterface.m */,
C7FB56F41DBFB480004E14EF /* SNTXPCSyncdInterface.h */,
C7FB56F51DBFB480004E14EF /* SNTXPCSyncdInterface.m */,
D221000F20AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.h */,
D221001020AB35F3003C65C2 /* SNTXPCUnprivilegedControlInterface.m */,
);
path = common;
sourceTree = "<group>";
@@ -756,6 +762,7 @@
isa = PBXGroup;
children = (
0DA73CA519363C9F0056D7C4 /* DataLayer */,
C748E8A020696001006CFD1B /* Logs */,
0D9A7F411759330500035EB5 /* main.m */,
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */,
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */,
@@ -769,8 +776,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 */,
@@ -807,6 +812,7 @@
isa = PBXGroup;
children = (
C7DA62F81E241A02009BDF2C /* SNTCommandBundleInfo.m */,
0D10D18320C19445008251ED /* SNTCommandCacheHistogram.m */,
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */,
0DCD5FBE1909D64A006B445C /* SNTCommandFileInfo.m */,
0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */,
@@ -844,6 +850,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 = (
@@ -922,8 +941,6 @@
0D260DA818B68E12002A0B55 /* Sources */,
0D260DA918B68E12002A0B55 /* Frameworks */,
0D260DAA18B68E12002A0B55 /* Resources */,
D49A3AB950AFD99741E9AF89 /* [CP] Embed Pods Frameworks */,
23869BA352E2C86DEFE62819 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -942,7 +959,6 @@
0DD98E671A5DD02000A754C6 /* Update Version Info */,
0D35BD9A18FD71CE00921A21 /* Sources */,
0D35BD9B18FD71CE00921A21 /* Frameworks */,
2737FE8516A33567D3449943 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -962,8 +978,6 @@
0D385DB2180DE4A900418BC6 /* Sources */,
0D385DB3180DE4A900418BC6 /* Frameworks */,
0D385DB4180DE4A900418BC6 /* Resources */,
BA20035148DDEF5808B2C7EF /* [CP] Embed Pods Frameworks */,
DDE76075391100F3BCE3634E /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1005,7 +1019,6 @@
0DD98E661A5DCED300A754C6 /* Update Version Info */,
0D9A7F391759330400035EB5 /* Sources */,
0D9A7F3A1759330400035EB5 /* Frameworks */,
531BBB5BA4BF953D628D29AB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1026,7 +1039,6 @@
C78227501E1C3C58006EB2D6 /* Sources */,
C78227511E1C3C58006EB2D6 /* Frameworks */,
C78227521E1C3C58006EB2D6 /* Resources */,
FCF4BDAA180BD63C32AC85DE /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -1043,7 +1055,7 @@
0D91BCA8174E8A6500131A7D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
LastUpgradeCheck = 0910;
TargetAttributes = {
0D260DAB18B68E12002A0B55 = {
TestTargetID = 0D385DB5180DE4A900418BC6;
@@ -1091,6 +1103,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 */,
);
@@ -1215,13 +1228,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 */ = {
@@ -1230,58 +1246,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 */ = {
@@ -1290,13 +1264,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 */ = {
@@ -1305,28 +1282,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 */ = {
@@ -1352,58 +1317,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 */
@@ -1421,19 +1344,20 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81133DB01F3A76F700917FF9 /* SNTCommand.m in Sources */,
C714F8B21D8044FE00700EDF /* SNTCommandController.m in Sources */,
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 */,
@@ -1443,15 +1367,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 */,
@@ -1462,6 +1384,7 @@
0DD0D492194F9BEF005F27EB /* SNTLogging.m in Sources */,
0DE71A761B95F7F900518526 /* SNTCachedDecision.m in Sources */,
0DCD605919115E5A006B445C /* SNTXPCNotifierInterface.m in Sources */,
D221001720AB360B003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */,
0DE50F691912B0CD007B2B0C /* SNTRule.m in Sources */,
0D202D1B1CDD465400A88F16 /* SNTCommandSyncState.m in Sources */,
C73A4B9A1DC10753007B6789 /* SNTSyncdQueue.m in Sources */,
@@ -1472,6 +1395,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81133DB11F3A77C600917FF9 /* SNTCommand.m in Sources */,
0DA73CA21934F88D0056D7C4 /* SNTLogging.m in Sources */,
0D35BDB518FD84F600921A21 /* SNTCommandSync.m in Sources */,
0DCD5FBF1909D64A006B445C /* SNTCommandFileInfo.m in Sources */,
@@ -1480,15 +1404,16 @@
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 */,
0D10BE871A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
0DE4C8A618FF3B1700466D04 /* SNTCommandFlushCache.m in Sources */,
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */,
D221001420AB3609003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */,
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */,
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */,
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
@@ -1510,12 +1435,12 @@
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 */,
0DCD605119115A06006B445C /* SNTXPCNotifierInterface.m in Sources */,
0DB77FD91CCE824A004DF060 /* SNTBlockMessage.m in Sources */,
D221001620AB360A003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */,
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */,
0D89310E1C931979002E8D74 /* SNTXPCControlInterface.m in Sources */,
0D385DF2180DE51600418BC6 /* SNTMessageWindowController.m in Sources */,
@@ -1524,7 +1449,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 */,
@@ -1548,29 +1472,30 @@
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 */,
0DB8ACC1185662DC00FEF9C7 /* SNTApplication.m in Sources */,
0D9A7F421759330500035EB5 /* main.m in Sources */,
0DA73C9F1934F8100056D7C4 /* SNTLogging.m in Sources */,
D221001320AB35FB003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */,
C7C721B11E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m in Sources */,
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 */,
);
@@ -1581,11 +1506,11 @@
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 */,
C7BBA67E1E54C7E200F1E6A8 /* SNTXPCNotifierInterface.m in Sources */,
D221001520AB360A003C65C2 /* SNTXPCUnprivilegedControlInterface.m in Sources */,
C7479F071E5374BF0054C1CF /* SNTXPCControlInterface.m in Sources */,
C7479F091E5374E50054C1CF /* SNTRule.m in Sources */,
C79A23581E23F7E80037AFA8 /* main.m in Sources */,
@@ -1673,6 +1598,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
OTHER_CODE_SIGN_FLAGS = "";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fcxx-modules",
@@ -1707,6 +1633,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
OTHER_CODE_SIGN_FLAGS = "";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-fcxx-modules",
@@ -1967,11 +1894,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;
@@ -1995,13 +1945,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;
@@ -2017,6 +1991,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;
@@ -2055,6 +2030,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

@@ -0,0 +1,139 @@
cmake_minimum_required(VERSION 3.10.0)
project(Santa)
function(CompileXib output_file_path_variable input_file_path)
get_filename_component(input_file_name "${input_file_path}" NAME_WE)
set(output_file_path "${CMAKE_CURRENT_BINARY_DIR}/${input_file_name}.nib")
add_custom_command(
OUTPUT "${output_file_path}"
COMMAND ibtool --compile "${output_file_path}" "${input_file_path}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Compiling: ${input_file_path}"
)
set("${output_file_path_variable}" "${output_file_path}" PARENT_SCOPE)
endfunction()
# It is important to only use absolute file paths with actool
function(CompileAssets asset_file_list_variable)
set(asset_file_list
"${CMAKE_CURRENT_BINARY_DIR}/AppIcon.icns"
"${CMAKE_CURRENT_BINARY_DIR}/Assets.car"
)
add_custom_command(
OUTPUT ${asset_file_list}
COMMAND xcrun actool --output-format=human-readable-text --notices --warnings --errors --platform macosx --minimum-deployment-target ${MACOSX_VERSION_MIN} --target-device mac --app-icon AppIcon --output-partial-info-plist "${CMAKE_CURRENT_BINARY_DIR}/Assets.plist" --compile "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Images.xcassets"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Packaging resources"
)
set("${asset_file_list_variable}" ${asset_file_list} PARENT_SCOPE)
endfunction()
function(main)
# Include all files to make IDEs happy
set(PROJECT_SOURCEFILES
SNTAboutWindowController.h
SNTAboutWindowController.m
SNTAccessibleTextField.h
SNTAccessibleTextField.m
SNTAppDelegate.h
SNTAppDelegate.m
SNTMessageWindow.h
SNTMessageWindow.m
SNTMessageWindowController.h
SNTMessageWindowController.m
SNTNotificationManager.h
SNTNotificationManager.m
main.m
# The "common" folder contains some of the files required to build this target
"${CMAKE_SOURCE_DIR}/Source/common/SNTConfigurator.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCControlInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCUnprivilegedControlInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTBlockMessage.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTRule.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTStoredEvent.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTSystemInfo.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCBundleServiceInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTXPCNotifierInterface.m"
"${CMAKE_SOURCE_DIR}/Source/common/SNTLogging.m"
)
set(PROJECT_XIBFILES
"${CMAKE_CURRENT_SOURCE_DIR}/Resources/AboutWindow.xib"
"${CMAKE_CURRENT_SOURCE_DIR}/Resources/MessageWindow.xib"
)
foreach(xib_file ${PROJECT_XIBFILES})
CompileXib(output_nib_file_path "${xib_file}")
list(APPEND PROJECT_RESOURCES "${output_nib_file_path}")
list(APPEND PROJECT_SOURCEFILES "${output_nib_file_path}")
endforeach()
CompileAssets(asset_file_list)
foreach(asset_file ${asset_file_list})
list(APPEND PROJECT_RESOURCES "${asset_file}")
list(APPEND PROJECT_SOURCEFILES "${asset_file}")
endforeach()
add_executable("${PROJECT_NAME}" MACOSX_BUNDLE ${PROJECT_SOURCEFILES})
target_link_libraries("${PROJECT_NAME}" PRIVATE -ObjC)
set_target_properties("${PROJECT_NAME}" PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "com.google.SantaGUI"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Resources/SantaGUI-Info.plist"
RESOURCE "${PROJECT_RESOURCES}"
)
target_link_libraries("${PROJECT_NAME}" PRIVATE
MOLCertificate MOLCodesignChecker MOLXPCConnection
"-framework Cocoa"
)
target_compile_options("${PROJECT_NAME}" PRIVATE
-fobjc-arc -Wno-everything -fmodules
-mmacosx-version-min=${MACOSX_VERSION_MIN}
)
if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
target_compile_options("${PROJECT_NAME}" PRIVATE -g3)
endif()
target_compile_definitions("${PROJECT_NAME}" PRIVATE
COCOAPODS=1
SANTAGUI=1
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions("${PROJECT_NAME}" PRIVATE DEBUG=1)
else()
target_compile_definitions("${PROJECT_NAME}" PRIVATE NDEBUG=1)
endif()
target_include_directories("${PROJECT_NAME}" PRIVATE
"${CMAKE_SOURCE_DIR}/Source/SantaGUI"
"${CMAKE_SOURCE_DIR}/Source/common"
"${CMAKE_SOURCE_DIR}/Source/santad"
)
add_custom_command(TARGET "${PROJECT_NAME}" POST_BUILD
COMMAND codesign --force --verify --verbose --sign "${CODESIGN_IDENTITY}" "${CMAKE_BINARY_DIR}/Source/SantaGUI/Santa.app"
COMMENT "Signing ${PROJECT_NAME} with the following identity: ${CODESIGN_IDENTITY}"
)
# Ignore errors about the missing RESOURCE destination missing; this is a cmake bug
install(TARGETS "${PROJECT_NAME}" BUNDLE DESTINATION "/Applications")
endfunction()
main()

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

@@ -9,20 +9,24 @@
<key>NSHumanReadableCopyright</key>
<string>Google, Inc.</string>
<key>CFBundleIdentifier</key>
<string>com.google.${PRODUCT_NAME:rfc1034identifier}GUI</string>
<string>com.google.SantaGUI</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<string>Santa</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<string>Santa</string>
<key>CFBundleVersion</key>
<string>TO.BE.FILLED</string>
<string>${SANTA_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>TO.BE.FILLED</string>
<string>${SANTA_VERSION}</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<string>${MACOSX_VERSION_MIN}</string>
<key>LSUIElement</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
</dict>
</plist>

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:kDefaultConfigFilePath
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,8 +78,8 @@
// Create listener for return connection from daemon.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.daemonListener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.daemonListener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
self.daemonListener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.daemonListener.privilegedInterface = [SNTXPCNotifierInterface notifierInterface];
self.daemonListener.exportedObject = self.notificationManager;
self.daemonListener.acceptedHandler = ^{
dispatch_semaphore_signal(sema);
@@ -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,8 +115,8 @@
// Create listener for return connection from the bundle service.
NSXPCListener *listener = [NSXPCListener anonymousListener];
self.bundleListener = [[SNTXPCConnection alloc] initServerWithListener:listener];
self.bundleListener.exportedInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
self.bundleListener = [[MOLXPCConnection alloc] initServerWithListener:listener];
self.bundleListener.privilegedInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
self.bundleListener.exportedObject = self.notificationManager;
self.bundleListener.acceptedHandler = ^{
dispatch_semaphore_signal(sema);
@@ -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

@@ -92,20 +92,7 @@
+ (NSURL *)eventDetailURLForEvent:(SNTStoredEvent *)event {
SNTConfigurator *config = [SNTConfigurator configurator];
NSString *formatStr, *versionStr;
if (config.eventDetailBundleURL.length && event.fileBundleID) {
formatStr = config.eventDetailBundleURL;
versionStr = event.fileBundleVersion;
if (!versionStr) versionStr = event.fileBundleVersionString;
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%bundle_id%"
withString:event.fileBundleID];
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%bundle_ver%"
withString:versionStr];
} else {
formatStr = config.eventDetailURL;
}
NSString *formatStr = config.eventDetailURL;
if (!formatStr.length) return nil;
if (event.fileSHA256) {

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.
@@ -72,6 +72,20 @@ typedef NS_ENUM(NSInteger, SNTRuleTableError) {
SNTRuleTableErrorRemoveFailed
};
// This enum type is used to indicate what should be done with the related bundle events that are
// generated when an initiating blocked bundle event occurs.
typedef NS_ENUM(NSInteger, SNTBundleEventAction) {
SNTBundleEventActionDropEvents,
SNTBundleEventActionStoreEvents,
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,34 +12,28 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
#import "SNTCommonEnums.h"
///
/// 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
/// Default config file path
extern NSString *const kDefaultConfigFilePath;
#pragma mark - Daemon Settings
///
/// 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 kDefaultConfigFilePath;
/// 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 kDefaultConfigFilePath;
/// 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 kDefaultConfigFilePath;
///
@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
///
@@ -77,8 +116,6 @@ extern NSString *const kDefaultConfigFilePath;
///
/// When the user gets a block notification, a button can be displayed which will
/// take them to a web page with more information about that event.
/// There are two properties, one for individual binaries and one for binaries that are part
/// of a bundle. If the latter is not set the former will be used.
///
/// This property contains a kind of format string to be turned into the URL to send them to.
/// The following sequences will be replaced in the final URL:
@@ -86,15 +123,12 @@ extern NSString *const kDefaultConfigFilePath;
/// %file_sha% -- SHA-256 of the file that was blocked.
/// %machine_id% -- ID of the machine.
/// %username% -- executing user.
/// %bundle_id% -- bundle id of the binary, if applicable.
/// %bundle_ver% -- bundle version of the binary, if applicable.
///
/// @note: This is not an NSURL because the format-string parsing is done elsewhere.
///
/// If this item isn't set, the Open Event button will not be displayed.
///
@property(readonly, nonatomic) NSString *eventDetailURL;
@property(readonly, nonatomic) NSString *eventDetailBundleURL;
///
/// Related to the above property, this string represents the text to show on the button.
@@ -207,15 +241,8 @@ extern NSString *const kDefaultConfigFilePath;
+ (instancetype)configurator;
///
/// Designated initializer.
/// Clear the sync server configuration from the effective configuration.
///
/// @param filePath The path to the file to use as a backing store.
///
- (instancetype)initWithFilePath:(NSString *)filePath;
///
/// Re-read config data from disk.
///
- (void)reloadConfigData;
- (void)clearSyncState;
@end

View File

@@ -14,47 +14,35 @@
#import "SNTConfigurator.h"
#include <sys/stat.h>
#import "SNTLogging.h"
#import "SNTStrengthify.h"
#import "SNTSystemInfo.h"
@interface SNTConfigurator ()
@property NSString *configFilePath;
@property NSMutableDictionary *configData;
/// A NSUserDefaults object set to use the com.google.santa suite.
@property(readonly, nonatomic) NSUserDefaults *defaults;
/// Creating NSRegularExpression objects is not fast, so cache them.
@property NSRegularExpression *cachedFileChangesRegex;
@property NSRegularExpression *cachedWhitelistDirRegex;
@property NSRegularExpression *cachedBlacklistDirRegex;
// Keys and expected value types.
@property(readonly, nonatomic) NSDictionary *syncServerKeyTypes;
@property(readonly, nonatomic) NSDictionary *forcedConfigKeyTypes;
/// Array of keys that cannot be changed while santad is running if santad didn't make the change.
@property(readonly) NSArray *protectedKeys;
/// Holds the configurations from a sync server and mobileconfig.
@property NSMutableDictionary *syncState;
@property NSMutableDictionary *configState;
@end
@implementation SNTConfigurator
/// The hard-coded path to the config file
NSString *const kDefaultConfigFilePath = @"/var/db/santa/config.plist";
/// The hard-coded path to the sync state file.
NSString *const kSyncStateFilePath = @"/var/db/santa/sync-state.plist";
/// The keys in the config file
static NSString *const kClientModeKey = @"ClientMode";
static NSString *const kFileChangesRegexKey = @"FileChangesRegex";
static NSString *const kWhitelistRegexKey = @"WhitelistRegex";
static NSString *const kBlacklistRegexKey = @"BlacklistRegex";
static NSString *const kEnablePageZeroProtectionKey = @"EnablePageZeroProtection";
static NSString *const kMoreInfoURLKey = @"MoreInfoURL";
static NSString *const kEventDetailURLKey = @"EventDetailURL";
static NSString *const kEventDetailBundleURLKey = @"EventDetailBundleURL";
static NSString *const kEventDetailTextKey = @"EventDetailText";
static NSString *const kUnknownBlockMessage = @"UnknownBlockMessage";
static NSString *const kBannedBlockMessage = @"BannedBlockMessage";
static NSString *const kModeNotificationMonitor = @"ModeNotificationMonitor";
static NSString *const kModeNotificationLockdown = @"ModeNotificationLockdown";
/// The domain used by mobileconfig.
static NSString *const kMobileConfigDomain = @"com.google.santa";
/// The keys managed by a mobileconfig.
static NSString *const kSyncBaseURLKey = @"SyncBaseURL";
static NSString *const kFullSyncLastSuccess = @"FullSyncLastSuccess";
static NSString *const kRuleSyncLastSuccess = @"RuleSyncLastSuccess";
static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
static NSString *const kClientAuthCertificateFileKey = @"ClientAuthCertificateFile";
static NSString *const kClientAuthCertificatePasswordKey = @"ClientAuthCertificatePassword";
static NSString *const kClientAuthCertificateCNKey = @"ClientAuthCertificateCN";
@@ -64,18 +52,89 @@ static NSString *const kServerAuthRootsFileKey = @"ServerAuthRootsFile";
static NSString *const kMachineOwnerKey = @"MachineOwner";
static NSString *const kMachineIDKey = @"MachineID";
static NSString *const kMachineOwnerPlistFileKey = @"MachineOwnerPlist";
static NSString *const kMachineOwnerPlistKeyKey = @"MachineOwnerKey";
static NSString *const kMachineIDPlistFileKey = @"MachineIDPlist";
static NSString *const kMachineIDPlistKeyKey = @"MachineIDKey";
- (instancetype)initWithFilePath:(NSString *)filePath {
static NSString *const kMoreInfoURLKey = @"MoreInfoURL";
static NSString *const kEventDetailURLKey = @"EventDetailURL";
static NSString *const kEventDetailTextKey = @"EventDetailText";
static NSString *const kUnknownBlockMessage = @"UnknownBlockMessage";
static NSString *const kBannedBlockMessage = @"BannedBlockMessage";
static NSString *const kModeNotificationMonitor = @"ModeNotificationMonitor";
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";
// The keys managed by a sync server.
static NSString *const kFullSyncLastSuccess = @"FullSyncLastSuccess";
static NSString *const kRuleSyncLastSuccess = @"RuleSyncLastSuccess";
static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
- (instancetype)init {
self = [super init];
if (self) {
_configFilePath = filePath;
[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;
}
@@ -83,314 +142,431 @@ static NSString *const kMachineIDPlistKeyKey = @"MachineIDKey";
#pragma mark Singleton retriever
+ (instancetype)configurator {
static SNTConfigurator *sharedConfigurator = nil;
static SNTConfigurator *sharedConfigurator;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedConfigurator = [[SNTConfigurator alloc] initWithFilePath:kDefaultConfigFilePath];
sharedConfigurator = [[SNTConfigurator alloc] init];
});
return sharedConfigurator;
}
#pragma mark Protected Keys
+ (NSSet *)syncAndConfigStateSet {
static NSSet *set;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
set = [[self syncStateSet] setByAddingObjectsFromSet:[self configStateSet]];
});
return set;
}
- (NSArray *)protectedKeys {
return @[ kClientModeKey, kWhitelistRegexKey, kBlacklistRegexKey,
kFileChangesRegexKey, kSyncBaseURLKey ];
+ (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 saveConfigToDisk];
[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 saveConfigToDisk];
- (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 saveConfigToDisk];
- (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 saveConfigToDisk];
}
- (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 *)eventDetailBundleURL {
return self.configData[kEventDetailBundleURLKey];
}
- (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 saveConfigToDisk];
[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 saveConfigToDisk];
[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 saveConfigToDisk];
[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 {
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:self.configFilePath]) {
// As soon as saveConfigToDisk is called, reloadConfigData will be called again because
// of the SNTFileWatchers on the config path. No need to use dictionaryWithCapacity: here.
self.configData = [NSMutableDictionary dictionary];
self.configData[kClientModeKey] = @(SNTClientModeMonitor);
[self saveConfigToDisk];
return;
};
- (SNTEventLogType)eventLogType {
NSString *s = [self.configState[kEventLogType] lowercaseString];
return [s isEqualToString:@"syslog"] ? SNTEventLogTypeSyslog : SNTEventLogTypeFilelog;
}
NSError *error;
NSData *readData = [NSData dataWithContentsOfFile:self.configFilePath
options:NSDataReadingMappedIfSafe
error:&error];
if (error) {
LOGE(@"Could not read configuration file: %@, replacing.", [error localizedDescription]);
[self saveConfigToDisk];
return;
}
- (NSString *)eventLogPath {
return self.configState[kEventLogPath] ?: @"/var/db/santa/santa.log";
}
NSMutableDictionary *configData =
[NSPropertyListSerialization propertyListWithData:readData
options:NSPropertyListMutableContainers
format:NULL
error:&error];
if (error) {
LOGE(@"Could not parse configuration file: %@, replacing.", [error localizedDescription]);
[self saveConfigToDisk];
return;
}
if (self.syncBaseURL) {
// Ensure no-one is trying to change protected keys behind our back.
BOOL changed = NO;
if (geteuid() == 0) {
for (NSString *key in self.protectedKeys) {
if (((self.configData[key] && !configData[key]) ||
(!self.configData[key] && configData[key]) ||
(self.configData[key] && ![self.configData[key] isEqual:configData[key]]))) {
if (self.configData[key]) {
configData[key] = self.configData[key];
} else {
[configData removeObjectForKey:key];
}
changed = YES;
LOGI(@"Ignoring changed configuration key: %@", key);
}
}
}
self.configData = configData;
if (changed) [self saveConfigToDisk];
} else {
self.configData = configData;
}
- (BOOL)enableMachineIDDecoration {
NSNumber *number = self.configState[kEnableMachineIDDecoration];
return number ? [number boolValue] : NO;
}
#pragma mark Private
///
/// Saves the current @c self.configData to disk.
/// Update the syncState. Triggers a KVO event for all dependents.
///
- (void)saveConfigToDisk {
- (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];
});
}
///
/// 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 =
[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;
}
///
/// 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;
[self.configData writeToFile:self.configFilePath atomically:YES];
// 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];
}
- (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];
}
///
/// Update the configState. Triggers a KVO event for all dependents.
///
- (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,9 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <Foundation/Foundation.h>
@class MOLCodesignChecker;
///
/// Represents a binary on disk, providing access to details about that binary
@@ -123,6 +125,11 @@
///
- (BOOL)isDMG;
///
/// @return NSString describing the kind of file (executable, bundle, script, etc.)
///
- (NSString *)humanReadableFileType;
///
/// @return YES if this file has a bad/missing __PAGEZERO .
///
@@ -205,4 +212,16 @@
///
- (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
/// calls. You may pass in NULL for the error if you don't care to receive it.
///
- (MOLCodesignChecker *)codesignCheckerWithError:(NSError **)error;
@end

View File

@@ -15,14 +15,16 @@
#import "SNTFileInfo.h"
#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.
@@ -53,6 +55,8 @@
@property NSDictionary *infoDict;
@property NSDictionary *quarantineDict;
@property NSDictionary *cachedHeaders;
@property MOLCodesignChecker *cachedCodesignChecker;
@property(nonatomic) NSError *codesignCheckerError;
@end
@implementation SNTFileInfo
@@ -262,17 +266,30 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
}
- (BOOL)isDMG {
if (self.fileSize < 512) return NO;
NSUInteger last512 = self.fileSize - 512;
const char *magic = (const char *)[[self safeSubdataWithRange:NSMakeRange(last512, 4)] bytes];
return (magic && memcmp("koly", magic, 4) == 0);
}
- (NSString *)humanReadableFileType {
if ([self isExecutable]) return @"Executable";
if ([self isDylib]) return @"Dynamic Library";
if ([self isBundle]) return @"Bundle/Plugin";
if ([self isKext]) return @"Kernel Extension";
if ([self isScript]) return @"Script";
if ([self isXARArchive]) return @"XAR Archive";
if ([self isDMG]) return @"Disk Image";
return @"Unknown";
}
#pragma mark Page Zero
- (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];
@@ -300,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.
///
@@ -310,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];
@@ -428,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];
@@ -444,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;
@@ -555,8 +596,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
NSData *d = [self.fileHandle readDataOfLength:range.length];
if (d.length != range.length) return nil;
return d;
}
@catch (NSException *e) {
} @catch (NSException *e) {
return nil;
}
}
@@ -633,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;
}
///
@@ -680,4 +715,18 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
}
}
///
/// Cache and return a MOLCodeSignChecker for the given file. If there was an error creating the
/// code sign checker it will be returned in the passed-in error parameter.
///
- (MOLCodesignChecker *)codesignCheckerWithError:(NSError **)error {
if (!self.cachedCodesignChecker && !self.codesignCheckerError) {
NSError *e;
self.cachedCodesignChecker = [[MOLCodesignChecker alloc] initWithBinaryPath:self.path error:&e];
self.codesignCheckerError = e;
}
if (error) *error = self.codesignCheckerError;
return self.cachedCodesignChecker;
}
@end

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.
@@ -63,6 +62,8 @@ typedef enum {
// RESPONSES
ACTION_RESPOND_ALLOW = 20,
ACTION_RESPOND_DENY = 21,
ACTION_RESPOND_TOOLONG = 22,
ACTION_RESPOND_ACK = 23,
// NOTIFY
ACTION_NOTIFY_EXEC = 30,
@@ -79,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;
@@ -96,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

@@ -24,17 +24,17 @@
#include <IOKit/IOLib.h>
#ifdef DEBUG
#define LOGD(...) IOLog("D santa-driver: " __VA_ARGS__); IOLog("\n")
#define LOGD(format, ...) IOLog("D santa-driver: " format "\n", ##__VA_ARGS__);
#else // DEBUG
#define LOGD(...)
#define LOGD(format, ...)
#endif // DEBUG
#define LOGI(...) IOLog("I santa-driver: " __VA_ARGS__); IOLog("\n")
#define LOGW(...) IOLog("W santa-driver: " __VA_ARGS__); IOLog("\n")
#define LOGE(...) IOLog("E santa-driver: " __VA_ARGS__); IOLog("\n")
#define LOGI(format, ...) IOLog("I santa-driver: " format "\n", ##__VA_ARGS__);
#define LOGW(format, ...) IOLog("W santa-driver: " format "\n", ##__VA_ARGS__);
#define LOGE(format, ...) IOLog("E santa-driver: " format "\n", ##__VA_ARGS__);
#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,204 +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))) {
// 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,115 +12,56 @@
/// See the License for the specific language governing permissions and
/// limitations under the License.
@import Foundation;
#import <MOLCertificate/MOLCertificate.h>
#import "SNTCachedDecision.h"
#import "SNTCommonEnums.h"
#import "SNTKernelCommon.h"
#import "SNTXPCBundleServiceInterface.h"
@class SNTRule;
@class SNTStoredEvent;
@class SNTXPCConnection;
#import "SNTXPCUnprivilegedControlInterface.h"
///
/// Protocol implemented by santad and utilized by santactl
/// Protocol implemented by santad and utilized by santactl (privileged operations)
///
@protocol SNTDaemonControlXPC
@protocol SNTDaemonControlXPC <SNTUnprivilegedDaemonControlXPC>
///
/// Kernel ops
///
- (void)cacheCount:(void (^)(int64_t))reply;
- (void)flushCache:(void (^)(BOOL))reply;
- (void)checkCacheForVnodeID:(uint64_t)vnodeID withReply:(void (^)(santa_action_t))reply;
///
/// Database ops
///
- (void)databaseRuleCounts:(void (^)(int64_t binary, int64_t certificate))reply;
- (void)databaseRuleAddRules:(NSArray *)rules
cleanSlate:(BOOL)cleanSlate
reply:(void (^)(NSError *error))reply;
- (void)databaseEventCount:(void (^)(int64_t count))reply;
- (void)databaseEventsPending:(void (^)(NSArray *events))reply;
- (void)databaseRemoveEventsWithIDs:(NSArray *)ids;
- (void)databaseRuleForBinarySHA256:(NSString *)binarySHA256
certificateSHA256:(NSString *)certificateSHA256
reply:(void (^)(SNTRule *))reply;
///
/// Decision ops
///
///
/// @param filePath A Path to the file, can be nil.
/// @param fileSHA256 The pre-calculated SHA256 hash for the file, can be nil. If nil the hash will
/// be calculated by this method from the filePath.
/// @param certificateSHA256 A SHA256 hash of the signing certificate, can be nil.
/// @note If fileInfo and signingCertificate are both passed in, the most specific rule will be
/// returned. Binary rules take precedence over cert rules.
///
- (void)decisionForFilePath:(NSString *)filePath
fileSHA256:(NSString *)fileSHA256
certificateSHA256:(NSString *)certificateSHA256
reply:(void (^)(SNTEventState))reply;
///
/// Config ops
///
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply;
- (void)clientMode:(void (^)(SNTClientMode))reply;
- (void)setClientMode:(SNTClientMode)mode reply:(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)bundlesEnabled:(void (^)(BOOL))reply;
- (void)setBundlesEnabled:(BOOL)bundlesEnabled reply:(void (^)())reply;
///
/// GUI Ops
///
- (void)setNotificationListener:(NSXPCListenerEndpoint *)listener;
- (void)setBundleNotificationListener:(NSXPCListenerEndpoint *)listener;
- (void)setClientMode:(SNTClientMode)mode reply:(void (^)(void))reply;
- (void)setXsrfToken:(NSString *)token reply:(void (^)(void))reply;
- (void)setFullSyncLastSuccess:(NSDate *)date reply:(void (^)(void))reply;
- (void)setRuleSyncLastSuccess:(NSDate *)date reply:(void (^)(void))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)setBundlesEnabled:(BOOL)bundlesEnabled reply:(void (^)(void))reply;
///
/// Syncd Ops
///
- (void)setSyncdListener:(NSXPCListenerEndpoint *)listener;
- (void)pushNotifications:(void (^)(BOOL))reply;
- (void)postRuleSyncNotificationWithCustomMessage:(NSString *)message reply:(void (^)())reply;
///
/// Bundle Ops
///
- (void)hashBundleBinariesForEvent:(SNTStoredEvent *)event reply:(SNTBundleHashBlock)reply;
- (void)syncBundleEvent:(SNTStoredEvent *)event relatedEvents:(NSArray<SNTStoredEvent *> *)events;
- (void)postRuleSyncNotificationWithCustomMessage:(NSString *)message reply:(void (^)(void))reply;
@end
@interface SNTXPCControlInterface : NSObject
@interface SNTXPCControlInterface : SNTXPCUnprivilegedControlInterface
///
/// Returns the MachService ID for this service.
/// Internal method used to initialize the control interface
///
+ (NSString *)serviceId;
///
/// Returns an initialized NSXPCInterface for the SNTDaemonControlXPC protocol.
/// Ensures any methods that accept custom classes as arguments are set-up before returning
///
+ (NSXPCInterface *)controlInterface;
///
/// Retrieve a pre-configured SNTXPCConnection for communicating with santad.
/// Connections just needs any handlers set and then can be resumed and used.
///
+ (SNTXPCConnection *)configuredConnection;
+ (void)initializeControlInterface:(NSXPCInterface *)r;
@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
@@ -24,8 +25,8 @@
return @"SantaXPCControl";
}
+ (NSXPCInterface *)controlInterface {
NSXPCInterface *r = [NSXPCInterface interfaceWithProtocol:@protocol(SNTDaemonControlXPC)];
+ (void)initializeControlInterface:(NSXPCInterface *)r {
[super initializeControlInterface:r];
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTStoredEvent class], nil]
forSelector:@selector(databaseEventsPending:)
@@ -36,22 +37,17 @@
forSelector:@selector(databaseRuleAddRules:cleanSlate:reply:)
argumentIndex:0
ofReply:NO];
}
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTStoredEvent class], nil]
forSelector:@selector(hashBundleBinariesForEvent:reply:)
argumentIndex:1
ofReply:YES];
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTStoredEvent class], nil]
forSelector:@selector(syncBundleEvent:relatedEvents:)
argumentIndex:1
ofReply:NO];
+ (NSXPCInterface *)controlInterface {
NSXPCInterface *r = [NSXPCInterface interfaceWithProtocol:@protocol(SNTDaemonControlXPC)];
[self initializeControlInterface:r];
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"
@@ -20,9 +20,9 @@
/// Protocol implemented by santactl and utilized by santad
@protocol SNTSyncdXPC
- (void)postEventToSyncServer:(SNTStoredEvent *)event;
- (void)postBundleEventToSyncServer:(SNTStoredEvent *)event reply:(void (^)(BOOL))reply;
- (void)postBundleEventsToSyncServer:(NSArray<SNTStoredEvent *> *)events;
- (void)postEventsToSyncServer:(NSArray<SNTStoredEvent *> *)events isFromBundle:(BOOL)isFromBundle;
- (void)postBundleEventToSyncServer:(SNTStoredEvent *)event
reply:(void (^)(SNTBundleEventAction))reply;
- (void)isFCMListening:(void (^)(BOOL))reply;
@end

View File

@@ -22,7 +22,7 @@
NSXPCInterface *r = [NSXPCInterface interfaceWithProtocol:@protocol(SNTSyncdXPC)];
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTStoredEvent class], nil]
forSelector:@selector(postBundleEventsToSyncServer:)
forSelector:@selector(postEventsToSyncServer:isFromBundle:)
argumentIndex:0
ofReply:NO];

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