mirror of
https://github.com/google/santa.git
synced 2026-01-22 04:28:11 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ee6531627 | ||
|
|
1cf8ee09e1 | ||
|
|
4a2cf9d722 | ||
|
|
6a6a32c1cf | ||
|
|
ce03611b52 | ||
|
|
bbe9f83878 | ||
|
|
40e6c6aa92 | ||
|
|
9f6ccf092a | ||
|
|
d4ba4b082f | ||
|
|
cce43829eb | ||
|
|
c1bfbac2fe |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ Santa.xcodeproj/project.xcworkspace
|
||||
Santa.xcworkspace/xcuserdata
|
||||
Santa.xcworkspace/xcshareddata
|
||||
Source/DevelopmentTeam.xcconfig
|
||||
default.profraw
|
||||
|
||||
@@ -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
|
||||
|
||||
2
Conf/com.google.santa.newsyslog.conf
Normal file
2
Conf/com.google.santa.newsyslog.conf
Normal 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
|
||||
@@ -42,6 +42,7 @@ mkdir -p /usr/local/bin
|
||||
/bin/cp ${SOURCE}/conf/com.google.santad.plist /Library/LaunchDaemons
|
||||
/bin/cp ${SOURCE}/conf/com.google.santagui.plist /Library/LaunchAgents
|
||||
/bin/cp ${SOURCE}/conf/com.google.santa.asl.conf /etc/asl/
|
||||
/bin/cp ${SOURCE}/conf/com.google.santa.newsyslog.conf /etc/newsyslog.d/
|
||||
|
||||
# Reload syslogd to pick up ASL configuration change.
|
||||
/usr/bin/killall -HUP syslogd
|
||||
|
||||
@@ -19,6 +19,7 @@ user=$(/usr/bin/stat -f '%u' /dev/console)
|
||||
/bin/rm -f /Library/LaunchAgents/com.google.santagui.plist
|
||||
/bin/rm -f /Library/LaunchDaemons/com.google.santad.plist
|
||||
/bin/rm -f /private/etc/asl/com.google.santa.asl.conf
|
||||
/bin/rm -f /private/etc/newsyslog.d/com.google.santa.newsyslog.conf
|
||||
/bin/rm -f /usr/local/bin/santactl # just a symlink
|
||||
#uncomment to remove the config file and all databases, log files
|
||||
#/bin/rm -rf /var/db/santa
|
||||
|
||||
36
Podfile.lock
36
Podfile.lock
@@ -1,15 +1,15 @@
|
||||
PODS:
|
||||
- FMDB (2.6.2):
|
||||
- FMDB/standard (= 2.6.2)
|
||||
- FMDB/standard (2.6.2)
|
||||
- MOLAuthenticatingURLSession (2.2):
|
||||
- MOLCertificate (~> 1.5)
|
||||
- MOLCertificate (1.5)
|
||||
- MOLCodesignChecker (1.5):
|
||||
- MOLCertificate (~> 1.3)
|
||||
- MOLFCMClient (1.3):
|
||||
- MOLAuthenticatingURLSession (~> 2.1)
|
||||
- OCMock (3.4)
|
||||
- FMDB (2.7.2):
|
||||
- FMDB/standard (= 2.7.2)
|
||||
- FMDB/standard (2.7.2)
|
||||
- MOLAuthenticatingURLSession (2.4):
|
||||
- MOLCertificate (~> 1.8)
|
||||
- MOLCertificate (1.8)
|
||||
- MOLCodesignChecker (1.10):
|
||||
- MOLCertificate (~> 1.8)
|
||||
- MOLFCMClient (1.7):
|
||||
- MOLAuthenticatingURLSession (~> 2.4)
|
||||
- OCMock (3.4.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- FMDB
|
||||
@@ -20,13 +20,13 @@ DEPENDENCIES:
|
||||
- OCMock
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a
|
||||
MOLAuthenticatingURLSession: 5a5e31eb73248c3e92c79b9a285f031194e8404c
|
||||
MOLCertificate: c39cae866d24d36fbc78032affff83d401b5384a
|
||||
MOLCodesignChecker: fc9c64147811d7b0d0739127003e0630dff9213a
|
||||
MOLFCMClient: 13d8b42db9d750e772f09cc38fc453922fece09f
|
||||
OCMock: 35ae71d6a8fcc1b59434d561d1520b9dd4f15765
|
||||
FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
|
||||
MOLAuthenticatingURLSession: c238aa1c9a7b1077eb39a6f40204bfe76a7d204e
|
||||
MOLCertificate: c999513316d511c69f290fbf313dfe8dca4ad592
|
||||
MOLCodesignChecker: b0d5db9d2f9bd94e0fd093891a5d40e5ad77cbc0
|
||||
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
|
||||
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
|
||||
|
||||
PODFILE CHECKSUM: acd378b3727c923d912e09812da344f7375c14fe
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.4.0
|
||||
|
||||
15
README.md
15
README.md
@@ -15,7 +15,7 @@ execution decisions based on the contents of a SQLite database, a GUI agent that
|
||||
notifies the user in case of a block decision and a command-line utility for
|
||||
managing the system and synchronizing the database with a server.
|
||||
|
||||
Santa is not yet a 1.0. We're writing more tests, fixing bugs, working on TODOs
|
||||
Santa is not yet at 1.0. We're writing more tests, fixing bugs, working on TODOs
|
||||
and finishing up a security audit.
|
||||
|
||||
It is named Santa because it keeps track of binaries that are naughty or nice.
|
||||
@@ -29,21 +29,21 @@ The Santa docs are stored in the [Docs](https://github.com/google/santa/blob/mas
|
||||
Admin-Related Features
|
||||
========
|
||||
|
||||
* Multiple modes: In the default MONITOR mode, all binaries except
|
||||
* Multiple modes: In the default MONITOR mode, all binaries except
|
||||
those marked as blacklisted will be allowed to run, whilst being logged and recorded in the events database. In LOCKDOWN mode, only whitelisted binaries are
|
||||
allowed to run.
|
||||
|
||||
* Event logging: When the kext is loaded, all binary launches are logged.
|
||||
When in either mode, all unknown or denied binaries are stored in the database to enable later aggregation.
|
||||
|
||||
* Certificate-based rules, with override levels: Instead of relying on a binaries hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
|
||||
* Certificate-based rules, with override levels: Instead of relying on a binary's hash (or 'fingerprint'), executables can be whitelisted/blacklisted by their signing
|
||||
certificate. You can therefore trust/block all binaries by a given publisher that were signed with that cert across version updates. A
|
||||
binary can only be whitelisted by its certificate if its signature validates
|
||||
correctly, but a rule for a binaries fingerprint will override a decision for a
|
||||
correctly, but a rule for a binary's fingerprint will override a decision for a
|
||||
certificate; i.e. you can whitelist a certificate while blacklisting a binary
|
||||
signed with that certificate, or vice-versa.
|
||||
|
||||
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature as Managed Client for OS X's (the precursor to configuration profiles, which used the same implementation mechanism) Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and doesn't rely on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precendence.
|
||||
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature to that found in Managed Client (the precursor to configuration profiles, which used the same implementation mechanism), Application Launch Restrictions via the mcxalr binary. This implementation carries the added benefit of being configurable via regex, and not relying on LaunchServices. As detailed in the wiki, when evaluating rules this holds the lowest precendence.
|
||||
|
||||
* Failsafe cert rules: You cannot put in a deny rule that would block the certificate used to sign launchd, a.k.a. pid 1, and therefore all components used in macOS. The binaries in every OS update (and in some cases entire new versions) are therefore auto-whitelisted. This does not affect binaries from Apple's App Store, which use various certs that change regularly for common apps. Likewise, you cannot blacklist Santa itself, and Santa uses a distinct separate cert than other Google apps.
|
||||
|
||||
@@ -54,7 +54,7 @@ Santa is written with the intention of helping protect users from themselves.
|
||||
People often download malware and trust it, giving the malware credentials, or
|
||||
allowing unknown software to exfiltrate more data about your system. As a
|
||||
centrally managed component, Santa can help stop the spread of malware among a
|
||||
larger fleet of machines. Independently, Santa can aid in analyzing what is
|
||||
large fleet of machines. Independently, Santa can aid in analyzing what is
|
||||
running on your computer.
|
||||
|
||||
Santa is part of a defense-in-depth strategy, and you should continue to protect
|
||||
@@ -62,7 +62,6 @@ hosts in whatever other ways you see fit.
|
||||
|
||||
Get Help
|
||||
========
|
||||
|
||||
If you have questions or otherwise need help getting started, the
|
||||
[santa-dev](https://groups.google.com/forum/#!forum/santa-dev) group is a
|
||||
great place. Please consult the [wiki](https://github.com/google/santa/wiki) and [issues](https://github.com/google/santa/issues) as well.
|
||||
@@ -84,7 +83,7 @@ continue to work across OS versions.
|
||||
|
||||
Known Issues
|
||||
============
|
||||
Santa is not yet a 1.0 and we have some known issues to be aware of:
|
||||
Santa is not yet at 1.0 and we have some known issues to be aware of:
|
||||
|
||||
* Santa only blocks execution (execve and variants), it doesn't protect against
|
||||
dynamic libraries loaded with dlopen, libraries on disk that have been replaced, or
|
||||
|
||||
1
Rakefile
1
Rakefile
@@ -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}"
|
||||
|
||||
@@ -72,8 +72,6 @@
|
||||
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 */; };
|
||||
@@ -148,9 +146,6 @@
|
||||
0DEA5F7B1CF64C9200704398 /* sync_ruledownload_batch2.json in Resources */ = {isa = PBXBuildFile; fileRef = 0DEA5F781CF64C8B00704398 /* sync_ruledownload_batch2.json */; };
|
||||
0DEA5F7D1CF64EB600704398 /* SNTCommandSyncRuleDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */; };
|
||||
0DEFB7C01ACB28B000B92AAE /* SNTCommandSyncConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */; };
|
||||
0DEFB7C41ACDD80100B92AAE /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
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 */; };
|
||||
@@ -167,12 +162,16 @@
|
||||
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 */; };
|
||||
C78227631E1C3C7D006EB2D6 /* santabs.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = C78227541E1C3C58006EB2D6 /* santabs.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
C7943FE92028B855008D4F76 /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
C7943FEA2028C4F7008D4F76 /* SNTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7C31ACDD80100B92AAE /* SNTFileWatcher.m */; };
|
||||
C795ED901D80A5BE007CFF42 /* SNTPolicyProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */; };
|
||||
C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */; };
|
||||
C79A23581E23F7E80037AFA8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C79A23561E23F7E80037AFA8 /* main.m */; };
|
||||
@@ -346,8 +345,6 @@
|
||||
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>"; };
|
||||
@@ -416,9 +413,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; };
|
||||
@@ -437,6 +431,12 @@
|
||||
A6A91785C40257CC156B4F05 /* Pods-Santa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.release.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C11A10A5D6E112788769CF70 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C72E8D931D7F399900C86DD3 /* SNTCommandFileInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandFileInfoTest.m; sourceTree = "<group>"; };
|
||||
C748E8A1206964DE006CFD1B /* SNTEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
|
||||
C748E8A2206964DE006CFD1B /* SNTEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
|
||||
C748E8A520696594006CFD1B /* SNTFileEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTFileEventLog.h; sourceTree = "<group>"; };
|
||||
C748E8A620696595006CFD1B /* SNTFileEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTFileEventLog.m; sourceTree = "<group>"; };
|
||||
C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSyslogEventLog.h; sourceTree = "<group>"; };
|
||||
C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTSyslogEventLog.m; sourceTree = "<group>"; };
|
||||
C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = BundleExample.app; sourceTree = "<group>"; };
|
||||
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCheckCache.m; sourceTree = "<group>"; };
|
||||
C776A1051DEE160500A56616 /* SNTCommandSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncManager.h; sourceTree = "<group>"; };
|
||||
@@ -540,7 +540,6 @@
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
|
||||
0DD0D48E194F78F8005F27EB /* SNTFileInfoTest.m */,
|
||||
0DEFB7C71ACF0BFE00B92AAE /* SNTFileWatcherTest.m */,
|
||||
0DB537861AFD36EB00487F92 /* SNTRuleTableTest.m */,
|
||||
0D3AFBE618FB32CB0087BCEE /* SNTXPCConnectionTest.m */,
|
||||
);
|
||||
@@ -733,8 +732,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 */,
|
||||
@@ -763,6 +760,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DA73CA519363C9F0056D7C4 /* DataLayer */,
|
||||
C748E8A020696001006CFD1B /* Logs */,
|
||||
0D9A7F411759330500035EB5 /* main.m */,
|
||||
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */,
|
||||
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */,
|
||||
@@ -776,8 +774,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 */,
|
||||
@@ -851,6 +847,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 = (
|
||||
@@ -1448,8 +1457,9 @@
|
||||
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 */,
|
||||
@@ -1466,10 +1476,9 @@
|
||||
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 */,
|
||||
@@ -1516,7 +1525,6 @@
|
||||
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */,
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
|
||||
C7943FE92028B855008D4F76 /* SNTFileWatcher.m in Sources */,
|
||||
0DB77FDA1CD14092004DF060 /* SNTBlockMessage.m in Sources */,
|
||||
0D35BDA218FD71CE00921A21 /* main.m in Sources */,
|
||||
0DCD6043190ACCB8006B445C /* SNTFileInfo.m in Sources */,
|
||||
@@ -1535,7 +1543,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C7943FEA2028C4F7008D4F76 /* SNTFileWatcher.m in Sources */,
|
||||
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */,
|
||||
0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */,
|
||||
0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */,
|
||||
@@ -1573,6 +1580,7 @@
|
||||
0D8868091AC48A1100B86659 /* SNTSystemInfo.m in Sources */,
|
||||
0DE6788D1784A8C2007A9E52 /* SNTExecutionController.m in Sources */,
|
||||
0D10BE861A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */,
|
||||
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
|
||||
0DCD604B19105433006B445C /* SNTStoredEvent.m in Sources */,
|
||||
C7FB57001DBFC213004E14EF /* SNTSyncdQueue.m in Sources */,
|
||||
@@ -1583,7 +1591,6 @@
|
||||
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 */,
|
||||
@@ -1592,10 +1599,11 @@
|
||||
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 */,
|
||||
);
|
||||
@@ -2042,6 +2050,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;
|
||||
@@ -2080,6 +2089,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;
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
@import SecurityInterface.SFCertificatePanel;
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
#import "SNTBlockMessage.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTMessageWindow.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
|
||||
@@ -80,6 +80,12 @@ typedef NS_ENUM(NSInteger, SNTBundleEventAction) {
|
||||
SNTBundleEventActionSendEvents,
|
||||
};
|
||||
|
||||
// Indicates where to store event logs.
|
||||
typedef NS_ENUM(NSInteger, SNTEventLogType) {
|
||||
SNTEventLogTypeSyslog,
|
||||
SNTEventLogTypeFilelog,
|
||||
};
|
||||
|
||||
static const char *kKextPath = "/Library/Extensions/santa-driver.kext";
|
||||
static const char *kSantaDPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santad";
|
||||
static const char *kSantaCtlPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santactl";
|
||||
|
||||
@@ -79,6 +79,25 @@
|
||||
///
|
||||
@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;
|
||||
|
||||
#pragma mark - GUI Settings
|
||||
|
||||
///
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#import "SNTFileWatcher.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTStrengthify.h"
|
||||
#import "SNTSystemInfo.h"
|
||||
@@ -32,9 +31,6 @@
|
||||
/// Holds the configurations from a sync server and mobileconfig.
|
||||
@property NSMutableDictionary *syncState;
|
||||
@property NSMutableDictionary *configState;
|
||||
|
||||
/// Watcher for the sync-state.plist.
|
||||
@property(nonatomic) SNTFileWatcher *syncStateWatcher;
|
||||
@end
|
||||
|
||||
@implementation SNTConfigurator
|
||||
@@ -73,6 +69,9 @@ static NSString *const kEnablePageZeroProtectionKey = @"EnablePageZeroProtection
|
||||
|
||||
static NSString *const kFileChangesRegexKey = @"FileChangesRegex";
|
||||
|
||||
static NSString *const kEventLogType = @"EventLogType";
|
||||
static NSString *const kEventLogPath = @"EventLogPath";
|
||||
|
||||
// The keys managed by a sync server or mobileconfig.
|
||||
static NSString *const kClientModeKey = @"ClientMode";
|
||||
static NSString *const kWhitelistRegexKey = @"WhitelistRegex";
|
||||
@@ -86,40 +85,47 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
Class number = [NSNumber class];
|
||||
Class re = [NSRegularExpression class];
|
||||
Class date = [NSDate class];
|
||||
Class string = [NSString class];
|
||||
Class data = [NSData class];
|
||||
_syncServerKeyTypes = @{
|
||||
kClientModeKey : [NSNumber class],
|
||||
kWhitelistRegexKey : [NSRegularExpression class],
|
||||
kBlacklistRegexKey : [NSRegularExpression class],
|
||||
kFullSyncLastSuccess : [NSDate class],
|
||||
kRuleSyncLastSuccess : [NSDate class],
|
||||
kSyncCleanRequired : [NSNumber class]
|
||||
kClientModeKey : number,
|
||||
kWhitelistRegexKey : re,
|
||||
kBlacklistRegexKey : re,
|
||||
kFullSyncLastSuccess : date,
|
||||
kRuleSyncLastSuccess : date,
|
||||
kSyncCleanRequired : number
|
||||
};
|
||||
_forcedConfigKeyTypes = @{
|
||||
kClientModeKey : [NSNumber class],
|
||||
kFileChangesRegexKey : [NSRegularExpression class],
|
||||
kWhitelistRegexKey : [NSRegularExpression class],
|
||||
kBlacklistRegexKey : [NSRegularExpression class],
|
||||
kEnablePageZeroProtectionKey : [NSNumber class],
|
||||
kMoreInfoURLKey : [NSString class],
|
||||
kEventDetailURLKey : [NSString class],
|
||||
kEventDetailTextKey : [NSString class],
|
||||
kUnknownBlockMessage : [NSString class],
|
||||
kBannedBlockMessage : [NSString class],
|
||||
kModeNotificationMonitor : [NSString class],
|
||||
kModeNotificationLockdown : [NSString class],
|
||||
kSyncBaseURLKey : [NSString class],
|
||||
kClientAuthCertificateFileKey : [NSString class],
|
||||
kClientAuthCertificatePasswordKey : [NSString class],
|
||||
kClientAuthCertificateCNKey : [NSString class],
|
||||
kClientAuthCertificateIssuerKey : [NSString class],
|
||||
kServerAuthRootsDataKey : [NSData class],
|
||||
kServerAuthRootsFileKey : [NSString class],
|
||||
kMachineOwnerKey : [NSString class],
|
||||
kMachineIDKey : [NSString class],
|
||||
kMachineOwnerPlistFileKey : [NSString class],
|
||||
kMachineOwnerPlistKeyKey : [NSString class],
|
||||
kMachineIDPlistFileKey : [NSString class],
|
||||
kMachineIDPlistKeyKey : [NSString class],
|
||||
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,
|
||||
};
|
||||
_defaults = [NSUserDefaults standardUserDefaults];
|
||||
[_defaults addSuiteNamed:@"com.google.santa"];
|
||||
@@ -141,94 +147,137 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
return sharedConfigurator;
|
||||
}
|
||||
|
||||
+ (NSSet *)syncAndConfigStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [[self syncStateSet] setByAddingObjectsFromSet:[self configStateSet]];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (NSSet *)syncStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSSet setWithObject:NSStringFromSelector(@selector(syncState))];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (NSSet *)configStateSet {
|
||||
static NSSet *set;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSSet setWithObject:NSStringFromSelector(@selector(configState))];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
#pragma mark KVO Dependencies
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingClientMode {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingWhitelistPathRegex {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingBlacklistPathRegex {
|
||||
return [NSSet setWithObjects:@"syncState", @"configState", nil];
|
||||
return [self syncAndConfigStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingFileChangesRegex {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncBaseURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEnablePageZeroProtection {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMoreInfoURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEventDetailURL {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingEventDetailText {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingUnknownBlockMessage {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingBannedBlockMessage {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingModeNotificationMonitor {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingModeNotificationLockdown {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateFile {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificatePassword {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateCn {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncClientAuthCertificateIssuer {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsData {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSyncServerAuthRootsFile {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingFullSyncLastSuccess {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMachineOwner {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
return [self configStateSet];
|
||||
}
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingMachineID {
|
||||
return [NSSet setWithObject:@"configState"];
|
||||
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];
|
||||
}
|
||||
|
||||
#pragma mark Public Interface
|
||||
@@ -344,7 +393,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setFullSyncLastSuccess:(NSDate *)fullSyncLastSuccess {
|
||||
self.syncState[kFullSyncLastSuccess] = fullSyncLastSuccess;
|
||||
[self updateSyncStateForKey:kFullSyncLastSuccess value:fullSyncLastSuccess];
|
||||
self.ruleSyncLastSuccess = fullSyncLastSuccess;
|
||||
}
|
||||
|
||||
@@ -353,8 +402,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setRuleSyncLastSuccess:(NSDate *)ruleSyncLastSuccess {
|
||||
self.syncState[kRuleSyncLastSuccess] = ruleSyncLastSuccess;
|
||||
[self saveSyncStateToDisk];
|
||||
[self updateSyncStateForKey:kRuleSyncLastSuccess value:ruleSyncLastSuccess];
|
||||
}
|
||||
|
||||
- (BOOL)syncCleanRequired {
|
||||
@@ -362,8 +410,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
}
|
||||
|
||||
- (void)setSyncCleanRequired:(BOOL)syncCleanRequired {
|
||||
self.syncState[kSyncCleanRequired] = @(syncCleanRequired);
|
||||
[self saveSyncStateToDisk];
|
||||
[self updateSyncStateForKey:kSyncCleanRequired value:@(syncCleanRequired)];
|
||||
}
|
||||
|
||||
- (NSString *)machineOwner {
|
||||
@@ -395,17 +442,27 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
return machineId.length ? machineId : [SNTSystemInfo hardwareUUID];
|
||||
}
|
||||
|
||||
- (SNTEventLogType)eventLogType {
|
||||
NSString *s = [self.configState[kEventLogType] lowercaseString];
|
||||
return [s isEqualToString:@"syslog"] ? SNTEventLogTypeSyslog : SNTEventLogTypeFilelog;
|
||||
}
|
||||
|
||||
- (NSString *)eventLogPath {
|
||||
return self.configState[kEventLogPath] ?: @"/var/db/santa/santa.log";
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
///
|
||||
/// Update the syncState. Triggers a KVO event for all dependents.
|
||||
///
|
||||
- (BOOL)updateSyncStateForKey:(NSString *)key value:(id)value {
|
||||
NSMutableDictionary *syncState = self.syncState.mutableCopy;
|
||||
syncState[key] = value;
|
||||
self.syncState = syncState;
|
||||
[self saveSyncStateToDisk];
|
||||
return YES;
|
||||
- (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];
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
@@ -427,15 +484,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
WEAKIFY(self);
|
||||
self.syncStateWatcher = [[SNTFileWatcher alloc] initWithFilePath:kSyncStateFilePath
|
||||
handler:^(unsigned long data) {
|
||||
STRONGIFY(self);
|
||||
[self syncStateFileChanged:data];
|
||||
}];
|
||||
});
|
||||
return syncState;
|
||||
}
|
||||
|
||||
@@ -456,39 +504,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
|
||||
ofItemAtPath:kSyncStateFilePath error:NULL];
|
||||
}
|
||||
|
||||
///
|
||||
/// Ensure permissions are 0644.
|
||||
/// Revert any out-of-band changes.
|
||||
///
|
||||
- (void)syncStateFileChanged:(unsigned long)data {
|
||||
if (data & DISPATCH_VNODE_ATTRIB) {
|
||||
const char *cPath = [kSyncStateFilePath fileSystemRepresentation];
|
||||
struct stat fileStat;
|
||||
stat(cPath, &fileStat);
|
||||
int mask = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int desired = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
if (fileStat.st_uid != 0 || fileStat.st_gid != 0 || (fileStat.st_mode & mask) != desired) {
|
||||
LOGI(@"Sync state file permissions changed, fixing.");
|
||||
chown(cPath, 0, 0);
|
||||
chmod(cPath, desired);
|
||||
}
|
||||
} else {
|
||||
NSDictionary *newSyncState = [self readSyncStateFromDisk];
|
||||
for (NSString *key in self.syncState) {
|
||||
if (((self.syncState[key] && !newSyncState[key]) ||
|
||||
(!self.syncState[key] && newSyncState[key]) ||
|
||||
(self.syncState[key] && ![self.syncState[key] isEqualTo:newSyncState[key]]))) {
|
||||
// Ignore sync url and dates
|
||||
if ([key isEqualToString:kRuleSyncLastSuccess] ||
|
||||
[key isEqualToString:kFullSyncLastSuccess]) continue;
|
||||
LOGE(@"Sync state file changed, replacing");
|
||||
[self saveSyncStateToDisk];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearSyncState {
|
||||
self.syncState = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
@@ -212,6 +212,11 @@
|
||||
///
|
||||
- (NSUInteger)fileSize;
|
||||
|
||||
///
|
||||
/// @return The underlying file handle.
|
||||
///
|
||||
@property(readonly) NSFileHandle *fileHandle;
|
||||
|
||||
///
|
||||
/// @return Returns an instance of MOLCodeSignChecker initialized with the file's binary path.
|
||||
/// Both the MOLCodesignChecker and any resulting NSError are cached and returned on subsequent
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#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>
|
||||
@@ -287,7 +288,8 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
- (BOOL)isMissingPageZero {
|
||||
// This method only checks i386 arch because the kernel enforces this for other archs
|
||||
// See bsd/kern/mach_loader.c, search for enforce_hard_pagezero.
|
||||
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86]];
|
||||
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86
|
||||
cpuSubType:CPU_SUBTYPE_I386_ALL]];
|
||||
if (!x86Header) return NO;
|
||||
|
||||
struct mach_header *mh = (struct mach_header *)[x86Header.data bytes];
|
||||
@@ -443,7 +445,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
if (machHeader) {
|
||||
struct mach_header *mh = (struct mach_header *)[machHeader bytes];
|
||||
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader offset:0];
|
||||
machHeaders[[self nameForCPUType:mh->cputype]] = mhwo;
|
||||
machHeaders[[self nameForCPUType:mh->cputype cpuSubType:mh->cpusubtype]] = mhwo;
|
||||
} else {
|
||||
NSRange range = NSMakeRange(0, sizeof(struct fat_header));
|
||||
NSData *fatHeader = [self safeSubdataWithRange:range];
|
||||
@@ -459,11 +461,12 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
int offset = OSSwapBigToHostInt32(fat_arch[i].offset);
|
||||
int size = OSSwapBigToHostInt32(fat_arch[i].size);
|
||||
int cputype = OSSwapBigToHostInt(fat_arch[i].cputype);
|
||||
int cpusubtype = OSSwapBigToHostInt(fat_arch[i].cpusubtype);
|
||||
|
||||
range = NSMakeRange(offset, size);
|
||||
NSData *machHeader = [self parseSingleMachHeader:[self safeSubdataWithRange:range]];
|
||||
if (machHeader) {
|
||||
NSString *key = [self nameForCPUType:cputype];
|
||||
NSString *key = [self nameForCPUType:cputype cpuSubType:cpusubtype];
|
||||
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader
|
||||
offset:offset];
|
||||
machHeaders[key] = mhwo;
|
||||
@@ -647,20 +650,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;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -66,7 +66,7 @@ typedef enum {
|
||||
ACTION_RESPOND_DENY = 21,
|
||||
ACTION_RESPOND_TOOLONG = 22,
|
||||
ACTION_RESPOND_ACK = 23,
|
||||
|
||||
|
||||
// NOTIFY
|
||||
ACTION_NOTIFY_EXEC = 30,
|
||||
ACTION_NOTIFY_WRITE = 31,
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
@implementation SNTStoredEvent
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#import "SNTXPCConnection.h"
|
||||
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTStrengthify.h"
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import <pthread/pthread.h>
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
@@ -72,18 +72,18 @@
|
||||
}
|
||||
|
||||
- (void)attemptReconnection {
|
||||
[self performSelectorInBackground:@selector(createConnection) withObject:nil];
|
||||
[self performSelectorOnMainThread:@selector(createConnection) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
|
||||
#pragma mark SNTBundleServiceXPC Methods
|
||||
|
||||
// Connect to the SantaGUI
|
||||
- (void)setBundleNotificationListener:(NSXPCListenerEndpoint *)listener {
|
||||
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
|
||||
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
|
||||
[c resume];
|
||||
self.notifierConnection = c;
|
||||
dispatch_async(self.queue, ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
SNTXPCConnection *c = [[SNTXPCConnection alloc] initClientWithListener:listener];
|
||||
c.remoteInterface = [SNTXPCNotifierInterface bundleNotifierInterface];
|
||||
[c resume];
|
||||
self.notifierConnection = c;
|
||||
[self createConnection];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ static NSString *const kPageZero = @"Page Zero";
|
||||
static NSString *const kCodeSigned = @"Code-signed";
|
||||
static NSString *const kRule = @"Rule";
|
||||
static NSString *const kSigningChain = @"Signing Chain";
|
||||
static NSString *const kUniversalSigningChain = @"Universal Signing Chain";
|
||||
|
||||
// signing chain keys
|
||||
static NSString *const kCommonName = @"Common Name";
|
||||
@@ -115,6 +116,7 @@ typedef id (^SNTAttributeBlock)(SNTCommandFileInfo *, SNTFileInfo *);
|
||||
@property(readonly, copy, nonatomic) SNTAttributeBlock codeSigned;
|
||||
@property(readonly, copy, nonatomic) SNTAttributeBlock rule;
|
||||
@property(readonly, copy, nonatomic) SNTAttributeBlock signingChain;
|
||||
@property(readonly, copy, nonatomic) SNTAttributeBlock universalSigningChain;
|
||||
|
||||
// Mapping between property string keys and SNTAttributeBlocks
|
||||
@property(nonatomic) NSDictionary<NSString *, SNTAttributeBlock> *propertyMap;
|
||||
@@ -182,7 +184,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
+ (NSArray<NSString *> *)fileInfoKeys {
|
||||
return @[ kPath, kSHA256, kSHA1, kBundleName, kBundleVersion, kBundleVersionStr,
|
||||
kDownloadReferrerURL, kDownloadURL, kDownloadTimestamp, kDownloadAgent,
|
||||
kType, kPageZero, kCodeSigned, kRule, kSigningChain ];
|
||||
kType, kPageZero, kCodeSigned, kRule, kSigningChain, kUniversalSigningChain ];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)signingChainKeys {
|
||||
@@ -210,7 +212,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
kPageZero : self.pageZero,
|
||||
kCodeSigned : self.codeSigned,
|
||||
kRule : self.rule,
|
||||
kSigningChain : self.signingChain };
|
||||
kSigningChain : self.signingChain,
|
||||
kUniversalSigningChain : self.universalSigningChain };
|
||||
|
||||
_printQueue = dispatch_queue_create("com.google.santactl.print_queue", DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
@@ -325,6 +328,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
return @"Yes, but failed requirement validation";
|
||||
case errSecCSInfoPlistFailed:
|
||||
return @"Yes, but can't validate as Info.plist is missing";
|
||||
case errSecCSSignatureInvalid:
|
||||
if ([error.domain isEqualToString:@"com.google.molcodesignchecker"]) {
|
||||
return @"Yes, but signing is not consistent for all architectures";
|
||||
}
|
||||
default: {
|
||||
return [NSString stringWithFormat:@"Yes, but failed to validate (%ld)", error.code];
|
||||
}
|
||||
@@ -345,10 +352,11 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
dispatch_once(&token, ^{ [cmd.daemonConn resume]; });
|
||||
__block SNTEventState state;
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
|
||||
NSError *err;
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:&err];
|
||||
[[cmd.daemonConn remoteObjectProxy] decisionForFilePath:fileInfo.path
|
||||
fileSHA256:fileInfo.SHA256
|
||||
certificateSHA256:csc.leafCertificate.SHA256
|
||||
certificateSHA256:err ? nil : csc.leafCertificate.SHA256
|
||||
reply:^(SNTEventState s) {
|
||||
state = s;
|
||||
dispatch_semaphore_signal(sema);
|
||||
@@ -417,6 +425,46 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
};
|
||||
}
|
||||
|
||||
- (SNTAttributeBlock)universalSigningChain {
|
||||
return ^id (SNTCommandFileInfo *cmd, SNTFileInfo *fileInfo) {
|
||||
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
|
||||
if (csc.certificates.count) return nil;
|
||||
if (!csc.universalSigningInformation) return nil;
|
||||
NSMutableArray *universal = [NSMutableArray array];
|
||||
for (NSDictionary *arch in csc.universalSigningInformation) {
|
||||
[universal addObject:@{ @"arch" : arch.allKeys.firstObject }];
|
||||
int flags = [arch.allValues.firstObject[(__bridge id)kSecCodeInfoFlags] intValue];
|
||||
if (flags & kSecCodeSignatureAdhoc) {
|
||||
[universal addObject:@{ @"ad-hoc" : @YES }];
|
||||
continue;
|
||||
}
|
||||
NSArray *certs = arch.allValues.firstObject[(__bridge id)kSecCodeInfoCertificates];
|
||||
NSArray *chain = [MOLCertificate certificatesFromArray:certs];
|
||||
if (!chain.count) {
|
||||
[universal addObject:@{ @"unsigned" : @YES }];
|
||||
continue;
|
||||
}
|
||||
for (MOLCertificate *c in chain) {
|
||||
[universal addObject:@{
|
||||
kSHA256 : c.SHA256 ?: @"null",
|
||||
kSHA1 : c.SHA1 ?: @"null",
|
||||
kCommonName : c.commonName ?: @"null",
|
||||
kOrganization : c.orgName ?: @"null",
|
||||
kOrganizationalUnit : c.orgUnit ?: @"null",
|
||||
kValidFrom : [cmd.dateFormatter stringFromDate:c.validFrom] ?: @"null",
|
||||
kValidUntil : [cmd.dateFormatter stringFromDate:c.validUntil] ?: @"null"
|
||||
}];
|
||||
}
|
||||
}
|
||||
NSMutableSet *set = [NSMutableSet set];
|
||||
for (NSDictionary *cert in universal) {
|
||||
if (cert[@"arch"]) continue;
|
||||
[set addObject:cert];
|
||||
}
|
||||
return (set.count > 1) ? universal : nil;
|
||||
};
|
||||
}
|
||||
|
||||
# pragma mark -
|
||||
|
||||
// Entry point for the command.
|
||||
@@ -590,8 +638,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
} else {
|
||||
for (NSString *key in self.outputKeyList) {
|
||||
if (![outputDict objectForKey:key]) continue;
|
||||
if ([key isEqual:kSigningChain]) {
|
||||
[output appendString:[self stringForSigningChain:outputDict[key]]];
|
||||
if ([key isEqual:kSigningChain] || [key isEqual:kUniversalSigningChain]) {
|
||||
[output appendString:[self stringForSigningChain:outputDict[key] key:key]];
|
||||
} else {
|
||||
if (singleKey) {
|
||||
[output appendFormat:@"%@\n", outputDict[key]];
|
||||
@@ -728,14 +776,25 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSString *)stringForSigningChain:(NSArray *)signingChain {
|
||||
- (NSString *)stringForSigningChain:(NSArray *)signingChain key:(NSString *)key {
|
||||
if (!signingChain) return @"";
|
||||
NSMutableString *result = [NSMutableString string];
|
||||
[result appendFormat:@"%@:\n", kSigningChain];
|
||||
[result appendFormat:@"%@:\n", key];
|
||||
int i = 1;
|
||||
NSArray<NSString *> *certKeys = [[self class] signingChainKeys];
|
||||
for (NSDictionary *cert in signingChain) {
|
||||
if ([cert isEqual:[NSNull null]]) continue;
|
||||
if (cert[@"arch"]) {
|
||||
[result appendFormat:@" %2@\n", [@"Architecture: " stringByAppendingString:cert[@"arch"]]];
|
||||
i = 1;
|
||||
continue;
|
||||
} else if (cert[@"ad-hoc"]) {
|
||||
[result appendFormat:@" %2d. %-20@\n", i, @"ad-hoc"];
|
||||
continue;
|
||||
} else if (cert[@"unsigned"]) {
|
||||
[result appendFormat:@" %2d. %-20@\n", i, @"unsigned"];
|
||||
continue;
|
||||
}
|
||||
if (i > 1) [result appendFormat:@"\n"];
|
||||
[result appendString:[self stringForCertificate:cert withKeys:certKeys index:i]];
|
||||
i += 1;
|
||||
@@ -749,10 +808,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
BOOL firstKey = YES;
|
||||
for (NSString *key in keys) {
|
||||
if (firstKey) {
|
||||
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
|
||||
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
|
||||
firstKey = NO;
|
||||
} else {
|
||||
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
|
||||
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
|
||||
}
|
||||
}
|
||||
return result.copy;
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
#import "SNTCommand.h"
|
||||
#import "SNTCommandController.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTFileInfo.h"
|
||||
|
||||
@@ -178,7 +178,7 @@ static void reachabilityHandler(
|
||||
}
|
||||
|
||||
- (void)isFCMListening:(void (^)(BOOL))reply {
|
||||
reply((self.FCMClient.FCMToken != nil));
|
||||
reply(self.FCMClient.isConnected);
|
||||
}
|
||||
|
||||
#pragma mark push notification methods
|
||||
@@ -205,16 +205,17 @@ static void reachabilityHandler(
|
||||
[self processFCMMessage:message withMachineID:machineID];
|
||||
}];
|
||||
|
||||
self.FCMClient.connectionErrorHandler = ^(NSError *error) {
|
||||
self.FCMClient.connectionErrorHandler = ^(NSHTTPURLResponse *response, NSError *error) {
|
||||
STRONGIFY(self);
|
||||
LOGE(@"FCM connection error: %@", error);
|
||||
if (response) LOGE(@"FCM fatal response: %@", response);
|
||||
if (error) LOGE(@"FCM fatal error: %@", error);
|
||||
[self.FCMClient disconnect];
|
||||
self.FCMClient = nil;
|
||||
[self rescheduleTimerQueue:self.fullSyncTimer secondsFromNow:kDefaultFullSyncInterval];
|
||||
};
|
||||
|
||||
self.FCMClient.loggingBlock = ^(NSString *log) {
|
||||
LOGD(@"%@", log);
|
||||
LOGD(@"FCMClient: %@", log);
|
||||
};
|
||||
|
||||
[self.FCMClient connect];
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
#import "SNTEventTable.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@implementation SNTEventTable
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
|
||||
#import "SNTRuleTable.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTRule.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -23,15 +23,32 @@
|
||||
/// Logs execution and file write events to syslog
|
||||
///
|
||||
@interface SNTEventLog : NSObject
|
||||
|
||||
// Methods implemented by a concrete subclass.
|
||||
- (void)logDiskAppeared:(NSDictionary *)diskProperties;
|
||||
- (void)logDiskDisappeared:(NSDictionary *)diskProperties;
|
||||
|
||||
- (void)logFileModification:(santa_message_t)message;
|
||||
|
||||
- (void)saveDecisionDetails:(SNTCachedDecision *)cd;
|
||||
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message;
|
||||
- (void)logAllowedExecution:(santa_message_t)message;
|
||||
|
||||
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events;
|
||||
|
||||
// Getter and setter for cached decisions.
|
||||
- (SNTCachedDecision *)cachedDecisionForMessage:(santa_message_t)message;
|
||||
- (void)cacheDecision:(SNTCachedDecision *)cd;
|
||||
|
||||
// String formatter helpers.
|
||||
- (void)addArgsForPid:(pid_t)pid toString:(NSMutableString *)str;
|
||||
- (NSString *)diskImageForDevice:(NSString *)devPath;
|
||||
- (NSString *)nameForUID:(uid_t)uid;
|
||||
- (NSString *)nameForGID:(gid_t)gid;
|
||||
- (NSString *)sanitizeCString:(const char *)str ofLength:(NSUInteger)length;
|
||||
- (NSString *)sanitizeString:(NSString *)inStr;
|
||||
- (NSString *)serialForDevice:(NSString *)devPath;
|
||||
- (NSString *)originalPathForTranslocation:(santa_message_t)message;
|
||||
|
||||
// A cache for usernames and groups.
|
||||
@property(readonly, nonatomic) NSCache<NSNumber *, NSString *> *userNameMap;
|
||||
@property(readonly, nonatomic) NSCache<NSNumber *, NSString *> *groupNameMap;
|
||||
|
||||
// A UTC Date formatter.
|
||||
@property(readonly, nonatomic) NSDateFormatter *dateFormatter;
|
||||
@end
|
||||
@@ -1,4 +1,4 @@
|
||||
/// Copyright 2015 Google Inc. All rights reserved.
|
||||
/// 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.
|
||||
@@ -16,28 +16,14 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <grp.h>
|
||||
#include <libproc.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "SNTCachedDecision.h"
|
||||
#import "SNTCommonEnums.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTFileInfo.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@interface SNTEventLog ()
|
||||
@property NSMutableDictionary<NSNumber *, SNTCachedDecision *> *detailStore;
|
||||
@property dispatch_queue_t detailStoreQueue;
|
||||
|
||||
// Caches for uid->username and gid->groupname lookups.
|
||||
@property NSCache<NSNumber *, NSString *> *userNameMap;
|
||||
@property NSCache<NSNumber *, NSString *> *groupNameMap;
|
||||
|
||||
@property NSDateFormatter *dateFormatter;
|
||||
@end
|
||||
|
||||
@implementation SNTEventLog
|
||||
@@ -61,222 +47,47 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)saveDecisionDetails:(SNTCachedDecision *)cd {
|
||||
dispatch_sync(_detailStoreQueue, ^{
|
||||
_detailStore[@(cd.vnodeId)] = cd;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)logFileModification:(santa_message_t)message {
|
||||
NSString *action, *newpath;
|
||||
|
||||
NSString *path = @(message.path);
|
||||
|
||||
switch (message.action) {
|
||||
case ACTION_NOTIFY_DELETE: {
|
||||
action = @"DELETE";
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_EXCHANGE: {
|
||||
action = @"EXCHANGE";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_LINK: {
|
||||
action = @"LINK";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_RENAME: {
|
||||
action = @"RENAME";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_WRITE: {
|
||||
action = @"WRITE";
|
||||
break;
|
||||
}
|
||||
default: action = @"UNKNOWN"; break;
|
||||
}
|
||||
|
||||
// init the string with 2k capacity to avoid reallocs
|
||||
NSMutableString *outStr = [NSMutableString stringWithCapacity:2048];
|
||||
[outStr appendFormat:@"action=%@|path=%@", action, [self sanitizeString:path]];
|
||||
if (newpath) {
|
||||
[outStr appendFormat:@"|newpath=%@", [self sanitizeString:newpath]];
|
||||
}
|
||||
char ppath[PATH_MAX] = "(null)";
|
||||
proc_pidpath(message.pid, ppath, PATH_MAX);
|
||||
|
||||
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
|
||||
message.pid, message.ppid, message.pname, ppath,
|
||||
message.uid, [self nameForUID:message.uid],
|
||||
message.gid, [self nameForGID:message.gid]];
|
||||
LOGI(@"%@", outStr);
|
||||
}
|
||||
|
||||
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
|
||||
[self logExecution:message withDecision:cd];
|
||||
}
|
||||
|
||||
- (void)logAllowedExecution:(santa_message_t)message {
|
||||
__block SNTCachedDecision *cd;
|
||||
dispatch_sync(_detailStoreQueue, ^{
|
||||
cd = _detailStore[@(message.vnode_id)];
|
||||
});
|
||||
[self logExecution:message withDecision:cd];
|
||||
}
|
||||
|
||||
- (void)logExecution:(santa_message_t)message withDecision:(SNTCachedDecision *)cd {
|
||||
NSString *d, *r;
|
||||
BOOL logArgs = NO;
|
||||
|
||||
switch (cd.decision) {
|
||||
case SNTEventStateAllowBinary:
|
||||
d = @"ALLOW";
|
||||
r = @"BINARY";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowCertificate:
|
||||
d = @"ALLOW";
|
||||
r = @"CERT";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowScope:
|
||||
d = @"ALLOW";
|
||||
r = @"SCOPE";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowUnknown:
|
||||
d = @"ALLOW";
|
||||
r = @"UNKNOWN";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateBlockBinary:
|
||||
d = @"DENY";
|
||||
r = @"BINARY";
|
||||
break;
|
||||
case SNTEventStateBlockCertificate:
|
||||
d = @"DENY";
|
||||
r = @"CERT";
|
||||
break;
|
||||
case SNTEventStateBlockScope:
|
||||
d = @"DENY";
|
||||
r = @"SCOPE";
|
||||
break;
|
||||
case SNTEventStateBlockUnknown:
|
||||
d = @"DENY";
|
||||
r = @"UNKNOWN";
|
||||
break;
|
||||
default:
|
||||
d = @"ALLOW";
|
||||
r = @"NOTRUNNING";
|
||||
logArgs = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
// init the string with 4k capacity to avoid reallocs
|
||||
NSMutableString *outLog = [[NSMutableString alloc] initWithCapacity:4096];
|
||||
[outLog appendFormat:@"action=EXEC|decision=%@|reason=%@", d, r];
|
||||
|
||||
if (cd.decisionExtra) {
|
||||
[outLog appendFormat:@"|explain=%@", cd.decisionExtra];
|
||||
}
|
||||
|
||||
[outLog appendFormat:@"|sha256=%@", cd.sha256];
|
||||
|
||||
if (cd.certSHA256) {
|
||||
[outLog appendFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
|
||||
[self sanitizeString:cd.certCommonName]];
|
||||
}
|
||||
|
||||
if (cd.quarantineURL) {
|
||||
[outLog appendFormat:@"|quarantine_url=%@", [self sanitizeString:cd.quarantineURL]];
|
||||
}
|
||||
|
||||
NSString *mode;
|
||||
switch ([[SNTConfigurator configurator] clientMode]) {
|
||||
case SNTClientModeMonitor:
|
||||
mode = @"M"; break;
|
||||
case SNTClientModeLockdown:
|
||||
mode = @"L"; break;
|
||||
default:
|
||||
mode = @"U"; break;
|
||||
}
|
||||
|
||||
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
|
||||
message.pid, message.ppid,
|
||||
message.uid, [self nameForUID:message.uid],
|
||||
message.gid, [self nameForGID:message.gid],
|
||||
mode, [self sanitizeString:@(message.path)]];
|
||||
|
||||
// Check for app translocation by GateKeeper, and log original path if the case.
|
||||
NSString *originalPath = [self originalPathForTranslocation:message];
|
||||
if (originalPath) {
|
||||
[outLog appendFormat:@"|origpath=%@", [self sanitizeString:originalPath]];
|
||||
}
|
||||
|
||||
if (logArgs) {
|
||||
[self addArgsForPid:message.pid toString:outLog];
|
||||
}
|
||||
|
||||
LOGI(@"%@", outLog);
|
||||
}
|
||||
|
||||
- (void)logDiskAppeared:(NSDictionary *)diskProperties {
|
||||
NSString *dmgPath = @"";
|
||||
NSString *serial = @"";
|
||||
if ([diskProperties[@"DADeviceModel"] isEqual:@"Disk Image"]) {
|
||||
dmgPath = [self diskImageForDevice:diskProperties[@"DADevicePath"]];
|
||||
} else {
|
||||
serial = [self serialForDevice:diskProperties[@"DADevicePath"]];
|
||||
serial = [serial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
}
|
||||
|
||||
NSString *model = [NSString stringWithFormat:@"%@ %@",
|
||||
diskProperties[@"DADeviceVendor"] ?: @"",
|
||||
diskProperties[@"DADeviceModel"] ?: @""];
|
||||
model = [model stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
double appearance = [diskProperties[@"DAAppearanceTime"] doubleValue];
|
||||
NSString *appearanceDateString =
|
||||
[_dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:appearance]];
|
||||
|
||||
NSString *log =
|
||||
@"action=DISKAPPEAR|mount=%@|volume=%@|bsdname=%@|fs=%@|"
|
||||
@"model=%@|serial=%@|bus=%@|dmgpath=%@|appearance=%@";
|
||||
LOGI(log,
|
||||
[diskProperties[@"DAVolumePath"] path] ?: @"",
|
||||
diskProperties[@"DAVolumeName"] ?: @"",
|
||||
diskProperties[@"DAMediaBSDName"] ?: @"",
|
||||
diskProperties[@"DAVolumeKind"] ?: @"",
|
||||
model ?: @"",
|
||||
serial,
|
||||
diskProperties[@"DADeviceProtocol"] ?: @"",
|
||||
dmgPath,
|
||||
appearanceDateString);
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)logDiskDisappeared:(NSDictionary *)diskProperties {
|
||||
LOGI(@"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@",
|
||||
[diskProperties[@"DAVolumePath"] path] ?: @"",
|
||||
diskProperties[@"DAVolumeName"] ?: @"",
|
||||
diskProperties[@"DAMediaBSDName"]);
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)logFileModification:(santa_message_t)message {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)logAllowedExecution:(santa_message_t)message {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events {
|
||||
for (SNTStoredEvent *event in events) {
|
||||
LOGI(@"action=BUNDLE|sha256=%@|bundlehash=%@|bundlename=%@|bundleid=%@|bundlepath=%@|path=%@",
|
||||
event.fileSHA256,
|
||||
event.fileBundleHash,
|
||||
event.fileBundleName,
|
||||
event.fileBundleID,
|
||||
event.fileBundlePath,
|
||||
event.filePath);
|
||||
}
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
#pragma mark Helpers
|
||||
- (void)writeLog:(NSString *)log {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)cacheDecision:(SNTCachedDecision *)cd {
|
||||
dispatch_sync(self.detailStoreQueue, ^{
|
||||
self.detailStore[@(cd.vnodeId)] = cd;
|
||||
});
|
||||
}
|
||||
|
||||
- (SNTCachedDecision *)cachedDecisionForMessage:(santa_message_t)message {
|
||||
__block SNTCachedDecision *cd;
|
||||
dispatch_sync(self.detailStoreQueue, ^{
|
||||
cd = self.detailStore[@(message.vnode_id)];
|
||||
});
|
||||
return cd;
|
||||
}
|
||||
|
||||
/**
|
||||
Sanitizes a given string if necessary, otherwise returns the original.
|
||||
18
Source/santad/Logs/SNTFileEventLog.h
Normal file
18
Source/santad/Logs/SNTFileEventLog.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/// 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.
|
||||
|
||||
#import "SNTSyslogEventLog.h"
|
||||
|
||||
@interface SNTFileEventLog : SNTSyslogEventLog
|
||||
@end
|
||||
101
Source/santad/Logs/SNTFileEventLog.m
Normal file
101
Source/santad/Logs/SNTFileEventLog.m
Normal file
@@ -0,0 +1,101 @@
|
||||
/// 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.
|
||||
|
||||
#import "SNTFileEventLog.h"
|
||||
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTStrengthify.h"
|
||||
|
||||
@interface SNTFileEventLog ()
|
||||
@property NSFileHandle *fh;
|
||||
@property(readonly, nonatomic) dispatch_queue_t q;
|
||||
@property dispatch_source_t source;
|
||||
@property(readonly, nonatomic) dispatch_source_t timer;
|
||||
@property(readonly, nonatomic) NSString *path;
|
||||
@property(readonly, nonatomic) NSMutableData *buffer;
|
||||
@end
|
||||
|
||||
@implementation SNTFileEventLog
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_q = dispatch_queue_create("com.google.santa.file_event_log", DISPATCH_QUEUE_SERIAL);
|
||||
_path = [[SNTConfigurator configurator] eventLogPath];
|
||||
_fh = [self fileHandleForPath:_path];
|
||||
[self watchLogFile];
|
||||
// 8k buffer to batch logs for writing.
|
||||
_buffer = [NSMutableData dataWithCapacity:8192];
|
||||
// To avoid long lulls in the log being updated, flush the buffer every second.
|
||||
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _q);
|
||||
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC * 1, 0);
|
||||
WEAKIFY(self);
|
||||
dispatch_source_set_event_handler(_timer, ^{
|
||||
STRONGIFY(self);
|
||||
[self flushBuffer];
|
||||
});
|
||||
dispatch_resume(_timer);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSFileHandle *)fileHandleForPath:(NSString *)path {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
if (![fm fileExistsAtPath:path]) {
|
||||
[fm createFileAtPath:path contents:nil attributes:nil];
|
||||
}
|
||||
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:path];
|
||||
[fh seekToEndOfFile];
|
||||
return fh;
|
||||
}
|
||||
|
||||
- (void)watchLogFile {
|
||||
if (self.source) {
|
||||
dispatch_source_set_event_handler_f(self.source, NULL);
|
||||
dispatch_source_cancel(self.source);
|
||||
}
|
||||
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,
|
||||
self.fh.fileDescriptor,
|
||||
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
|
||||
self.q);
|
||||
WEAKIFY(self);
|
||||
dispatch_source_set_event_handler(self.source, ^{
|
||||
STRONGIFY(self);
|
||||
[self.fh closeFile];
|
||||
self.fh = [self fileHandleForPath:self.path];
|
||||
[self watchLogFile];
|
||||
});
|
||||
dispatch_resume(self.source);
|
||||
}
|
||||
|
||||
- (void)writeLog:(NSString *)log {
|
||||
dispatch_async(self.q, ^{
|
||||
NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]];
|
||||
NSString *outLog = [NSString stringWithFormat:@"[%@] I santad: %@\n", dateString, log];
|
||||
[self.buffer appendBytes:outLog.UTF8String
|
||||
length:[outLog lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
|
||||
// Avoid excessive calls to write() by batching logs.
|
||||
if (self.buffer.length >= 4096) {
|
||||
[self flushBuffer];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)flushBuffer {
|
||||
write(self.fh.fileDescriptor, self.buffer.bytes, self.buffer.length);
|
||||
[self.buffer setLength:0];
|
||||
}
|
||||
|
||||
@end
|
||||
18
Source/santad/Logs/SNTSyslogEventLog.h
Normal file
18
Source/santad/Logs/SNTSyslogEventLog.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/// 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.
|
||||
|
||||
#import "SNTEventLog.h"
|
||||
|
||||
@interface SNTSyslogEventLog : SNTEventLog
|
||||
@end
|
||||
242
Source/santad/Logs/SNTSyslogEventLog.m
Normal file
242
Source/santad/Logs/SNTSyslogEventLog.m
Normal file
@@ -0,0 +1,242 @@
|
||||
/// 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.
|
||||
|
||||
#import "SNTSyslogEventLog.h"
|
||||
|
||||
#import <libproc.h>
|
||||
|
||||
#import "SNTCachedDecision.h"
|
||||
#import "SNTConfigurator.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@implementation SNTSyslogEventLog
|
||||
|
||||
- (void)logFileModification:(santa_message_t)message {
|
||||
NSString *action, *newpath;
|
||||
|
||||
NSString *path = @(message.path);
|
||||
|
||||
switch (message.action) {
|
||||
case ACTION_NOTIFY_DELETE: {
|
||||
action = @"DELETE";
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_EXCHANGE: {
|
||||
action = @"EXCHANGE";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_LINK: {
|
||||
action = @"LINK";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_RENAME: {
|
||||
action = @"RENAME";
|
||||
newpath = @(message.newpath);
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_WRITE: {
|
||||
action = @"WRITE";
|
||||
break;
|
||||
}
|
||||
default: action = @"UNKNOWN"; break;
|
||||
}
|
||||
|
||||
// init the string with 2k capacity to avoid reallocs
|
||||
NSMutableString *outStr = [NSMutableString stringWithCapacity:2048];
|
||||
[outStr appendFormat:@"action=%@|path=%@", action, [self sanitizeString:path]];
|
||||
if (newpath) {
|
||||
[outStr appendFormat:@"|newpath=%@", [self sanitizeString:newpath]];
|
||||
}
|
||||
char ppath[PATH_MAX] = "(null)";
|
||||
proc_pidpath(message.pid, ppath, PATH_MAX);
|
||||
|
||||
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
|
||||
message.pid, message.ppid, message.pname, ppath,
|
||||
message.uid, [self nameForUID:message.uid],
|
||||
message.gid, [self nameForGID:message.gid]];
|
||||
|
||||
[self writeLog:outStr];
|
||||
}
|
||||
|
||||
- (void)logExecution:(santa_message_t)message withDecision:(SNTCachedDecision *)cd {
|
||||
NSString *d, *r;
|
||||
BOOL logArgs = NO;
|
||||
|
||||
switch (cd.decision) {
|
||||
case SNTEventStateAllowBinary:
|
||||
d = @"ALLOW";
|
||||
r = @"BINARY";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowCertificate:
|
||||
d = @"ALLOW";
|
||||
r = @"CERT";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowScope:
|
||||
d = @"ALLOW";
|
||||
r = @"SCOPE";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowUnknown:
|
||||
d = @"ALLOW";
|
||||
r = @"UNKNOWN";
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateBlockBinary:
|
||||
d = @"DENY";
|
||||
r = @"BINARY";
|
||||
break;
|
||||
case SNTEventStateBlockCertificate:
|
||||
d = @"DENY";
|
||||
r = @"CERT";
|
||||
break;
|
||||
case SNTEventStateBlockScope:
|
||||
d = @"DENY";
|
||||
r = @"SCOPE";
|
||||
break;
|
||||
case SNTEventStateBlockUnknown:
|
||||
d = @"DENY";
|
||||
r = @"UNKNOWN";
|
||||
break;
|
||||
default:
|
||||
d = @"ALLOW";
|
||||
r = @"NOTRUNNING";
|
||||
logArgs = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
// init the string with 4k capacity to avoid reallocs
|
||||
NSMutableString *outLog = [[NSMutableString alloc] initWithCapacity:4096];
|
||||
[outLog appendFormat:@"action=EXEC|decision=%@|reason=%@", d, r];
|
||||
|
||||
if (cd.decisionExtra) {
|
||||
[outLog appendFormat:@"|explain=%@", cd.decisionExtra];
|
||||
}
|
||||
|
||||
[outLog appendFormat:@"|sha256=%@", cd.sha256];
|
||||
|
||||
if (cd.certSHA256) {
|
||||
[outLog appendFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
|
||||
[self sanitizeString:cd.certCommonName]];
|
||||
}
|
||||
|
||||
if (cd.quarantineURL) {
|
||||
[outLog appendFormat:@"|quarantine_url=%@", [self sanitizeString:cd.quarantineURL]];
|
||||
}
|
||||
|
||||
NSString *mode;
|
||||
switch ([[SNTConfigurator configurator] clientMode]) {
|
||||
case SNTClientModeMonitor:
|
||||
mode = @"M"; break;
|
||||
case SNTClientModeLockdown:
|
||||
mode = @"L"; break;
|
||||
default:
|
||||
mode = @"U"; break;
|
||||
}
|
||||
|
||||
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
|
||||
message.pid, message.ppid,
|
||||
message.uid, [self nameForUID:message.uid],
|
||||
message.gid, [self nameForGID:message.gid],
|
||||
mode, [self sanitizeString:@(message.path)]];
|
||||
|
||||
// Check for app translocation by GateKeeper, and log original path if the case.
|
||||
NSString *originalPath = [self originalPathForTranslocation:message];
|
||||
if (originalPath) {
|
||||
[outLog appendFormat:@"|origpath=%@", [self sanitizeString:originalPath]];
|
||||
}
|
||||
|
||||
if (logArgs) {
|
||||
[self addArgsForPid:message.pid toString:outLog];
|
||||
}
|
||||
|
||||
[self writeLog:outLog];
|
||||
}
|
||||
|
||||
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
|
||||
[self logExecution:message withDecision:cd];
|
||||
}
|
||||
|
||||
- (void)logAllowedExecution:(santa_message_t)message {
|
||||
SNTCachedDecision *cd = [self cachedDecisionForMessage:message];
|
||||
[self logExecution:message withDecision:cd];
|
||||
}
|
||||
|
||||
- (void)logDiskAppeared:(NSDictionary *)diskProperties {
|
||||
NSString *dmgPath = @"";
|
||||
NSString *serial = @"";
|
||||
if ([diskProperties[@"DADeviceModel"] isEqual:@"Disk Image"]) {
|
||||
dmgPath = [self diskImageForDevice:diskProperties[@"DADevicePath"]];
|
||||
} else {
|
||||
serial = [self serialForDevice:diskProperties[@"DADevicePath"]];
|
||||
serial = [serial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
}
|
||||
|
||||
NSString *model = [NSString stringWithFormat:@"%@ %@",
|
||||
diskProperties[@"DADeviceVendor"] ?: @"",
|
||||
diskProperties[@"DADeviceModel"] ?: @""];
|
||||
model = [model stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
double a = [diskProperties[@"DAAppearanceTime"] doubleValue];
|
||||
NSString *appearanceDateString =
|
||||
[self.dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:a]];
|
||||
|
||||
NSString *format =
|
||||
@"action=DISKAPPEAR|mount=%@|volume=%@|bsdname=%@|fs=%@|"
|
||||
@"model=%@|serial=%@|bus=%@|dmgpath=%@|appearance=%@";
|
||||
NSString *outLog = [NSMutableString stringWithFormat:format,
|
||||
[diskProperties[@"DAVolumePath"] path] ?: @"",
|
||||
diskProperties[@"DAVolumeName"] ?: @"",
|
||||
diskProperties[@"DAMediaBSDName"] ?: @"",
|
||||
diskProperties[@"DAVolumeKind"] ?: @"",
|
||||
model ?: @"",
|
||||
serial,
|
||||
diskProperties[@"DADeviceProtocol"] ?: @"",
|
||||
dmgPath,
|
||||
appearanceDateString];
|
||||
[self writeLog:outLog];
|
||||
}
|
||||
|
||||
- (void)logDiskDisappeared:(NSDictionary *)diskProperties {
|
||||
NSString *format = @"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@";
|
||||
NSString *outLog = [NSMutableString stringWithFormat:format,
|
||||
[diskProperties[@"DAVolumePath"] path] ?: @"",
|
||||
diskProperties[@"DAVolumeName"] ?: @"",
|
||||
diskProperties[@"DAMediaBSDName"]];
|
||||
[self writeLog:outLog];
|
||||
}
|
||||
|
||||
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events {
|
||||
for (SNTStoredEvent *event in events) {
|
||||
NSString *format = @"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@";
|
||||
NSString *outLog = [NSMutableString stringWithFormat:format,
|
||||
event.fileSHA256,
|
||||
event.fileBundleHash,
|
||||
event.fileBundleName,
|
||||
event.fileBundleID,
|
||||
event.fileBundlePath,
|
||||
event.filePath];
|
||||
[self writeLog:outLog];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)writeLog:(NSString *)log {
|
||||
LOGI(@"%@", log);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -22,13 +22,14 @@
|
||||
#import "SNTDatabaseController.h"
|
||||
#import "SNTDriverManager.h"
|
||||
#import "SNTDropRootPrivs.h"
|
||||
#import "SNTEventLog.h"
|
||||
#import "SNTEventTable.h"
|
||||
#import "SNTExecutionController.h"
|
||||
#import "SNTFileEventLog.h"
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTNotificationQueue.h"
|
||||
#import "SNTRuleTable.h"
|
||||
#import "SNTSyncdQueue.h"
|
||||
#import "SNTSyslogEventLog.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
#import "SNTXPCNotifierInterface.h"
|
||||
@@ -68,7 +69,16 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
_eventLog = [[SNTEventLog alloc] init];
|
||||
// Choose an event logger.
|
||||
SNTConfigurator *configurator = [SNTConfigurator configurator];
|
||||
switch ([configurator eventLogType]) {
|
||||
case SNTEventLogTypeSyslog:
|
||||
_eventLog = [[SNTSyslogEventLog alloc] init];
|
||||
break;
|
||||
case SNTEventLogTypeFilelog:
|
||||
_eventLog = [[SNTFileEventLog alloc] init];
|
||||
break;
|
||||
}
|
||||
|
||||
self.notQueue = [[SNTNotificationQueue alloc] init];
|
||||
SNTSyncdQueue *syncdQueue = [[SNTSyncdQueue alloc] init];
|
||||
@@ -80,22 +90,22 @@
|
||||
|
||||
// Listen for actionable config changes.
|
||||
NSKeyValueObservingOptions bits = (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld);
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"clientMode"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"syncBaseURL"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"whitelistPathRegex"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[[SNTConfigurator configurator] addObserver:self
|
||||
forKeyPath:@"blacklistPathRegex"
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(clientMode))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(syncBaseURL))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(whitelistPathRegex))
|
||||
options:bits
|
||||
context:NULL];
|
||||
[configurator addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(blacklistPathRegex))
|
||||
options:bits
|
||||
context:NULL];
|
||||
|
||||
// Establish XPC listener for Santa and santactl connections
|
||||
SNTDaemonControlController *dc =
|
||||
@@ -270,23 +280,25 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSString *,id> *)change
|
||||
context:(void *)context {
|
||||
if ([keyPath isEqualToString:@"clientMode"]) {
|
||||
NSString *newKey = NSKeyValueChangeNewKey;
|
||||
NSString *oldKey = NSKeyValueChangeOldKey;
|
||||
if ([keyPath isEqualToString:NSStringFromSelector(@selector(clientMode))]) {
|
||||
SNTClientMode new =
|
||||
[change[@"new"] isKindOfClass:[NSNumber class]] ? [change[@"new"] longLongValue] : 0;
|
||||
[change[newKey] isKindOfClass:[NSNumber class]] ? [change[newKey] longLongValue] : 0;
|
||||
SNTClientMode old =
|
||||
[change[@"old"] isKindOfClass:[NSNumber class]] ? [change[@"old"] longLongValue] : 0;
|
||||
[change[oldKey] isKindOfClass:[NSNumber class]] ? [change[oldKey] longLongValue] : 0;
|
||||
if (new != old) [self clientModeDidChange:new];
|
||||
} else if ([keyPath isEqualToString:@"syncBaseURL"]) {
|
||||
NSURL *new = [change[@"new"] isKindOfClass:[NSURL class]] ? change[@"new"] : nil;
|
||||
NSURL *old = [change[@"old"] isKindOfClass:[NSURL class]] ? change[@"old"] : nil;
|
||||
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(syncBaseURL))]) {
|
||||
NSURL *new = [change[newKey] isKindOfClass:[NSURL class]] ? change[newKey] : nil;
|
||||
NSURL *old = [change[oldKey] isKindOfClass:[NSURL class]] ? change[oldKey] : nil;
|
||||
if (!new && !old) return;
|
||||
if (![new.absoluteString isEqualToString:old.absoluteString]) [self syncBaseURLDidChange:new];
|
||||
} else if ([keyPath isEqualToString:@"whitelistPathRegex"] ||
|
||||
[keyPath isEqualToString:@"blacklistPathRegex"]) {
|
||||
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(whitelistPathRegex))] ||
|
||||
[keyPath isEqualToString:NSStringFromSelector(@selector(blacklistPathRegex))]) {
|
||||
NSRegularExpression *new =
|
||||
[change[@"new"] isKindOfClass:[NSRegularExpression class]] ? change[@"new"] : nil;
|
||||
[change[newKey] isKindOfClass:[NSRegularExpression class]] ? change[newKey] : nil;
|
||||
NSRegularExpression *old =
|
||||
[change[@"old"] isKindOfClass:[NSRegularExpression class]] ? change[@"old"] : nil;
|
||||
[change[oldKey] isKindOfClass:[NSRegularExpression class]] ? change[oldKey] : nil;
|
||||
if (!new && !old) return;
|
||||
if (![new.pattern isEqualToString:old.pattern]) {
|
||||
LOGI(@"Changed [white|black]list regex, flushing cache");
|
||||
@@ -306,11 +318,17 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
|
||||
- (void)syncBaseURLDidChange:(NSURL *)syncBaseURL {
|
||||
if (syncBaseURL) {
|
||||
LOGI(@"Starting santactl with new SyncBaseURL: %@", syncBaseURL);
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:[SNTConfigurator configurator]
|
||||
selector:@selector(clearSyncState)
|
||||
object:nil];
|
||||
[self startSyncd];
|
||||
} else {
|
||||
LOGI(@"SyncBaseURL removed, killing santactl pid: %i", self.syncdPID);
|
||||
[self stopSyncd];
|
||||
[[SNTConfigurator configurator] clearSyncState];
|
||||
// Keep the syncState active for 10 min in case com.apple.ManagedClient is flapping.
|
||||
[[SNTConfigurator configurator] performSelector:@selector(clearSyncState)
|
||||
withObject:nil
|
||||
afterDelay:600];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@ double watchdogRAMPeak = 0;
|
||||
bs.remoteInterface = [SNTXPCBundleServiceInterface bundleServiceInterface];
|
||||
[bs resume];
|
||||
[[bs remoteObjectProxy] setBundleNotificationListener:listener];
|
||||
[bs invalidate];
|
||||
}
|
||||
|
||||
#pragma mark syncd Ops
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#include "SNTLogging.h"
|
||||
|
||||
#import "MOLCertificate.h"
|
||||
#import "MOLCodesignChecker.h"
|
||||
#import <MOLCodesignChecker/MOLCodesignChecker.h>
|
||||
|
||||
#import "SNTBlockMessage.h"
|
||||
#import "SNTCachedDecision.h"
|
||||
#import "SNTCommonEnums.h"
|
||||
@@ -117,9 +117,11 @@ static size_t kLargeBinarySize = 30 * 1024 * 1024;
|
||||
|
||||
// Get codesigning info about the file.
|
||||
NSError *csError;
|
||||
MOLCodesignChecker *csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
|
||||
error:&csError];
|
||||
// Ignore codesigning if there are any errors with the signature.
|
||||
MOLCodesignChecker *csInfo =
|
||||
[[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
|
||||
fileDescriptor:binInfo.fileHandle.fileDescriptor
|
||||
error:&csError];
|
||||
// Ignore codesigning if there are any errors with the signature.
|
||||
if (csError) csInfo = nil;
|
||||
|
||||
// Actually make the decision.
|
||||
@@ -134,7 +136,7 @@ static size_t kLargeBinarySize = 30 * 1024 * 1024;
|
||||
(SNTEventStateAllow & cd.decision) ? ACTION_RESPOND_ALLOW : ACTION_RESPOND_DENY;
|
||||
|
||||
// Save decision details for logging the execution later.
|
||||
if (action == ACTION_RESPOND_ALLOW) [_eventLog saveDecisionDetails:cd];
|
||||
if (action == ACTION_RESPOND_ALLOW) [_eventLog cacheDecision:cd];
|
||||
|
||||
// Send the decision to the kernel.
|
||||
[_driverManager postToKernelAction:action forVnodeID:cd.vnodeId];
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#import "SNTCommonEnums.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
|
||||
#import <MOLCertificate.h>
|
||||
#import <MOLCertificate/MOLCertificate.h>
|
||||
|
||||
@class SNTCachedDecision;
|
||||
@class SNTFileInfo;
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
///
|
||||
- (NSString *)fileIsScopeWhitelisted:(SNTFileInfo *)fi {
|
||||
if (!fi) return nil;
|
||||
|
||||
|
||||
// Determine if file is within a whitelisted path
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] whitelistPathRegex];
|
||||
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
- (NSString *)fileIsScopeBlacklisted:(SNTFileInfo *)fi {
|
||||
if (!fi) return nil;
|
||||
|
||||
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] blacklistPathRegex];
|
||||
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
|
||||
return @"Blacklist Regex";
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
|
||||
self.mockCodesignChecker = OCMClassMock([MOLCodesignChecker class]);
|
||||
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
|
||||
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY error:[OCMArg setTo:NULL]])
|
||||
|
||||
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY
|
||||
fileDescriptor:0
|
||||
error:[OCMArg setTo:NULL]])
|
||||
.andReturn(self.mockCodesignChecker);
|
||||
|
||||
self.mockConfigurator = OCMClassMock([SNTConfigurator class]);
|
||||
|
||||
@@ -1,140 +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 XCTest;
|
||||
|
||||
#import "SNTFileWatcher.h"
|
||||
|
||||
@interface SNTFileWatcherTest : XCTestCase
|
||||
@property NSFileManager *fm;
|
||||
@property NSString *file;
|
||||
@end
|
||||
|
||||
@implementation SNTFileWatcherTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.fm = [NSFileManager defaultManager];
|
||||
self.file = [NSTemporaryDirectory() stringByAppendingString:@"SNTFileWatcherTest_File"];
|
||||
[self createFile];
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[self deleteFile];
|
||||
usleep(10000);
|
||||
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)createFile {
|
||||
[self.fm createFileAtPath:self.file contents:nil attributes:nil];
|
||||
}
|
||||
|
||||
- (void)deleteFile {
|
||||
[self.fm removeItemAtPath:self.file error:NULL];
|
||||
}
|
||||
|
||||
- (void)testPlainInit {
|
||||
XCTAssertThrows([[SNTFileWatcher alloc] init]);
|
||||
}
|
||||
|
||||
- (void)testInitFileExists {
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
[exp fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testInitNewFile {
|
||||
[self deleteFile];
|
||||
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Init: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
[exp fulfill];
|
||||
}];
|
||||
|
||||
[self createFile];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileChanged {
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Changed: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if (!fulfilled && [d isEqual:@"0x8BADF00D"]) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
sleep(1);
|
||||
|
||||
[[@"0x8BADF00D" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:NO];
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileReplaced {
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Replaced: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
NSString *d = [NSString stringWithContentsOfFile:self.file
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
if (!fulfilled && [d isEqual:@"0xFACEFEED"]) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
[[@"0xFACEFEED" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:self.file atomically:YES];
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFileExtended {
|
||||
int fd = open(self.file.fileSystemRepresentation, O_WRONLY);
|
||||
write(fd, "0xDEAD", 6);
|
||||
|
||||
__block BOOL fulfilled = NO;
|
||||
__weak XCTestExpectation *exp = [self expectationWithDescription:@"Extended: callback called"];
|
||||
__unused SNTFileWatcher *sut = [[SNTFileWatcher alloc] initWithFilePath:self.file
|
||||
handler:^(unsigned long data) {
|
||||
int file = open(self.file.fileSystemRepresentation, O_RDONLY);
|
||||
char fileData[10];
|
||||
read(file, fileData, 10);
|
||||
|
||||
if (!fulfilled && strncmp(fileData, "0xDEADBEEF", 10) == 0) {
|
||||
fulfilled = YES;
|
||||
[exp fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
write(fd, "BEEF", 4);
|
||||
close(fd);
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user