From 4a2cf9d722a4e2d88f6b0b560ddee44706ea4442 Mon Sep 17 00:00:00 2001 From: Tom Burgin Date: Tue, 3 Apr 2018 13:15:12 -0400 Subject: [PATCH] santad: event logger (#246) * kext symbols * santad: Create FileLog and Syslog options * review updates * review updates * be a good citizen and let go of things you do not need --- .gitignore | 1 + Conf/Package/Makefile | 10 + Conf/com.google.santa.newsyslog.conf | 2 + Conf/install.sh | 1 + Conf/uninstall.sh | 1 + Rakefile | 1 + Santa.xcodeproj/project.pbxproj | 42 +++- Source/common/SNTCommonEnums.h | 6 + Source/common/SNTConfigurator.h | 19 ++ Source/common/SNTConfigurator.m | 22 ++ Source/common/SNTLogging.m | 8 +- Source/santad/{ => Logs}/SNTEventLog.h | 29 ++- Source/santad/{ => Logs}/SNTEventLog.m | 238 ++------------------ Source/santad/Logs/SNTFileEventLog.h | 18 ++ Source/santad/Logs/SNTFileEventLog.m | 101 +++++++++ Source/santad/Logs/SNTSyslogEventLog.h | 18 ++ Source/santad/Logs/SNTSyslogEventLog.m | 242 +++++++++++++++++++++ Source/santad/SNTApplication.m | 15 +- Source/santad/SNTDaemonControlController.m | 1 + Source/santad/SNTExecutionController.m | 2 +- 20 files changed, 541 insertions(+), 236 deletions(-) create mode 100644 Conf/com.google.santa.newsyslog.conf rename Source/santad/{ => Logs}/SNTEventLog.h (53%) rename Source/santad/{ => Logs}/SNTEventLog.m (63%) create mode 100644 Source/santad/Logs/SNTFileEventLog.h create mode 100644 Source/santad/Logs/SNTFileEventLog.m create mode 100644 Source/santad/Logs/SNTSyslogEventLog.h create mode 100644 Source/santad/Logs/SNTSyslogEventLog.m diff --git a/.gitignore b/.gitignore index d3614ab8a..dc5e7d6ab 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ Santa.xcodeproj/project.xcworkspace Santa.xcworkspace/xcuserdata Santa.xcworkspace/xcshareddata Source/DevelopmentTeam.xcconfig +default.profraw diff --git a/Conf/Package/Makefile b/Conf/Package/Makefile index 056f7e3c7..b6f786b3a 100644 --- a/Conf/Package/Makefile +++ b/Conf/Package/Makefile @@ -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 diff --git a/Conf/com.google.santa.newsyslog.conf b/Conf/com.google.santa.newsyslog.conf new file mode 100644 index 000000000..f5296c11b --- /dev/null +++ b/Conf/com.google.santa.newsyslog.conf @@ -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 diff --git a/Conf/install.sh b/Conf/install.sh index 895a75b5f..abeed5556 100755 --- a/Conf/install.sh +++ b/Conf/install.sh @@ -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 diff --git a/Conf/uninstall.sh b/Conf/uninstall.sh index e9cc4fa52..3812975c6 100755 --- a/Conf/uninstall.sh +++ b/Conf/uninstall.sh @@ -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 diff --git a/Rakefile b/Rakefile index 148af12b5..ad4b6d68f 100644 --- a/Rakefile +++ b/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}" diff --git a/Santa.xcodeproj/project.pbxproj b/Santa.xcodeproj/project.pbxproj index 3bdf01751..aa301f2a2 100644 --- a/Santa.xcodeproj/project.pbxproj +++ b/Santa.xcodeproj/project.pbxproj @@ -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 */; }; @@ -164,6 +162,12 @@ C7479F051E53704E0054C1CF /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; }; C7479F071E5374BF0054C1CF /* SNTXPCControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD605419115D17006B445C /* SNTXPCControlInterface.m */; }; C7479F091E5374E50054C1CF /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; }; + C748E8A3206964E1006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; }; + C748E8A4206964EE006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; }; + C748E8A720696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; }; + C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; }; + C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; }; + C748E8B120697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; }; C74D6CC61EEB3B9B00BB5A33 /* BundleExample.app in Resources */ = {isa = PBXBuildFile; fileRef = C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */; }; C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */; }; C776A1071DEE160500A56616 /* SNTCommandSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C776A1061DEE160500A56616 /* SNTCommandSyncManager.m */; }; @@ -341,8 +345,6 @@ 0D5058CF1CB70123008784BA /* SNTStrengthify.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTStrengthify.h; sourceTree = ""; }; 0D536ED51B8E7A2E0039A26D /* bad_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = bad_pagezero; sourceTree = ""; }; 0D536ED61B8E7A2E0039A26D /* missing_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = missing_pagezero; sourceTree = ""; }; - 0D536ED91B94E9230039A26D /* SNTEventLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = ""; }; - 0D536EDA1B94E9230039A26D /* SNTEventLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = ""; }; 0D63DD5A1906FCB400D346C4 /* SNTDatabaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDatabaseController.h; sourceTree = ""; }; 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDatabaseController.m; sourceTree = ""; }; 0D668E7F18D1121700E29A8B /* SNTMessageWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTMessageWindow.h; sourceTree = ""; }; @@ -429,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 = ""; }; 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 = ""; }; + C748E8A1206964DE006CFD1B /* SNTEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = ""; }; + C748E8A2206964DE006CFD1B /* SNTEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = ""; }; + C748E8A520696594006CFD1B /* SNTFileEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTFileEventLog.h; sourceTree = ""; }; + C748E8A620696595006CFD1B /* SNTFileEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTFileEventLog.m; sourceTree = ""; }; + C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSyslogEventLog.h; sourceTree = ""; }; + C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTSyslogEventLog.m; sourceTree = ""; }; C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = BundleExample.app; sourceTree = ""; }; C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCheckCache.m; sourceTree = ""; }; C776A1051DEE160500A56616 /* SNTCommandSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncManager.h; sourceTree = ""; }; @@ -752,6 +760,7 @@ isa = PBXGroup; children = ( 0DA73CA519363C9F0056D7C4 /* DataLayer */, + C748E8A020696001006CFD1B /* Logs */, 0D9A7F411759330500035EB5 /* main.m */, 0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */, 0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */, @@ -765,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 */, @@ -840,6 +847,19 @@ name = Frameworks; sourceTree = ""; }; + 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 = ""; + }; C79A23541E23F7E80037AFA8 /* santabs */ = { isa = PBXGroup; children = ( @@ -1437,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 */, @@ -1457,6 +1478,7 @@ 0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */, C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */, C72E8D941D7F399900C86DD3 /* SNTCommandFileInfoTest.m in Sources */, + C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */, 0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */, 0DE5B54C1C92722300C00603 /* SNTNotificationQueue.m in Sources */, 0DEA5F651CF6057D00704398 /* SNTCommandSyncEventUpload.m in Sources */, @@ -1558,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 */, @@ -1576,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 */, ); @@ -2026,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; @@ -2064,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; diff --git a/Source/common/SNTCommonEnums.h b/Source/common/SNTCommonEnums.h index bde0c7a7f..3f17bdcf3 100644 --- a/Source/common/SNTCommonEnums.h +++ b/Source/common/SNTCommonEnums.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"; diff --git a/Source/common/SNTConfigurator.h b/Source/common/SNTConfigurator.h index 808e3b565..33c574d59 100644 --- a/Source/common/SNTConfigurator.h +++ b/Source/common/SNTConfigurator.h @@ -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 /// diff --git a/Source/common/SNTConfigurator.m b/Source/common/SNTConfigurator.m index 7e9db3c1e..0b8b7e6c1 100644 --- a/Source/common/SNTConfigurator.m +++ b/Source/common/SNTConfigurator.m @@ -69,6 +69,9 @@ @implementation SNTConfigurator 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"; @@ -121,6 +124,8 @@ - (instancetype)init { kMachineOwnerPlistKeyKey : string, kMachineIDPlistFileKey : string, kMachineIDPlistKeyKey : string, + kEventLogType : string, + kEventLogPath : string, }; _defaults = [NSUserDefaults standardUserDefaults]; [_defaults addSuiteNamed:@"com.google.santa"]; @@ -267,6 +272,14 @@ + (NSSet *)keyPathsForValuesAffectingSyncCleanRequired { return [self syncStateSet]; } ++ (NSSet *)keyPathsForValuesAffectingEventLogType { + return [self configStateSet]; +} + ++ (NSSet *)keyPathsForValuesAffectingEventLogPath { + return [self configStateSet]; +} + #pragma mark Public Interface - (SNTClientMode)clientMode { @@ -429,6 +442,15 @@ - (NSString *)machineID { 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 /// diff --git a/Source/common/SNTLogging.m b/Source/common/SNTLogging.m index c5f60044b..022216a15 100644 --- a/Source/common/SNTLogging.m +++ b/Source/common/SNTLogging.m @@ -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]; diff --git a/Source/santad/SNTEventLog.h b/Source/santad/Logs/SNTEventLog.h similarity index 53% rename from Source/santad/SNTEventLog.h rename to Source/santad/Logs/SNTEventLog.h index cc80ae1ae..5f36ce6fd 100644 --- a/Source/santad/SNTEventLog.h +++ b/Source/santad/Logs/SNTEventLog.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 *)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 *userNameMap; +@property(readonly, nonatomic) NSCache *groupNameMap; + +// A UTC Date formatter. +@property(readonly, nonatomic) NSDateFormatter *dateFormatter; @end diff --git a/Source/santad/SNTEventLog.m b/Source/santad/Logs/SNTEventLog.m similarity index 63% rename from Source/santad/SNTEventLog.m rename to Source/santad/Logs/SNTEventLog.m index 86cad8bf0..cc60c307a 100644 --- a/Source/santad/SNTEventLog.m +++ b/Source/santad/Logs/SNTEventLog.m @@ -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,29 +16,14 @@ #include #include -#include #include #include -#import - #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 *detailStore; @property dispatch_queue_t detailStoreQueue; - -// Caches for uid->username and gid->groupname lookups. -@property NSCache *userNameMap; -@property NSCache *groupNameMap; - -@property NSDateFormatter *dateFormatter; @end @implementation SNTEventLog @@ -62,223 +47,48 @@ - (instancetype)init { return self; } -- (void)saveDecisionDetails:(SNTCachedDecision *)cd { - dispatch_sync(_detailStoreQueue, ^{ - _detailStore[@(cd.vnodeId)] = cd; - }); +- (void)logDiskAppeared:(NSDictionary *)diskProperties { + [self doesNotRecognizeSelector:_cmd]; } -- (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; - } +- (void)logDiskDisappeared:(NSDictionary *)diskProperties { + [self doesNotRecognizeSelector:_cmd]; +} - // 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)logFileModification:(santa_message_t)message { + [self doesNotRecognizeSelector:_cmd]; } - (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message { - [self logExecution:message withDecision:cd]; + [self doesNotRecognizeSelector:_cmd]; } - (void)logAllowedExecution:(santa_message_t)message { - __block SNTCachedDecision *cd; - dispatch_sync(_detailStoreQueue, ^{ - cd = _detailStore[@(message.vnode_id)]; - }); - [self logExecution:message withDecision:cd]; + [self doesNotRecognizeSelector:_cmd]; } -- (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)logBundleHashingEvents:(NSArray *)events { + [self doesNotRecognizeSelector:_cmd]; } -- (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); +- (void)writeLog:(NSString *)log { + [self doesNotRecognizeSelector:_cmd]; } -- (void)logDiskDisappeared:(NSDictionary *)diskProperties { - LOGI(@"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@", - [diskProperties[@"DAVolumePath"] path] ?: @"", - diskProperties[@"DAVolumeName"] ?: @"", - diskProperties[@"DAMediaBSDName"]); +- (void)cacheDecision:(SNTCachedDecision *)cd { + dispatch_sync(self.detailStoreQueue, ^{ + self.detailStore[@(cd.vnodeId)] = cd; + }); } -- (void)logBundleHashingEvents:(NSArray *)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); - } +- (SNTCachedDecision *)cachedDecisionForMessage:(santa_message_t)message { + __block SNTCachedDecision *cd; + dispatch_sync(self.detailStoreQueue, ^{ + cd = self.detailStore[@(message.vnode_id)]; + }); + return cd; } -#pragma mark Helpers - /** Sanitizes a given string if necessary, otherwise returns the original. */ diff --git a/Source/santad/Logs/SNTFileEventLog.h b/Source/santad/Logs/SNTFileEventLog.h new file mode 100644 index 000000000..f95db70fd --- /dev/null +++ b/Source/santad/Logs/SNTFileEventLog.h @@ -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 diff --git a/Source/santad/Logs/SNTFileEventLog.m b/Source/santad/Logs/SNTFileEventLog.m new file mode 100644 index 000000000..1859bf864 --- /dev/null +++ b/Source/santad/Logs/SNTFileEventLog.m @@ -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 diff --git a/Source/santad/Logs/SNTSyslogEventLog.h b/Source/santad/Logs/SNTSyslogEventLog.h new file mode 100644 index 000000000..4a5dc6303 --- /dev/null +++ b/Source/santad/Logs/SNTSyslogEventLog.h @@ -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 diff --git a/Source/santad/Logs/SNTSyslogEventLog.m b/Source/santad/Logs/SNTSyslogEventLog.m new file mode 100644 index 000000000..6798d1ef3 --- /dev/null +++ b/Source/santad/Logs/SNTSyslogEventLog.m @@ -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 + +#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 *)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 diff --git a/Source/santad/SNTApplication.m b/Source/santad/SNTApplication.m index a5e2fbc68..bcb338e83 100644 --- a/Source/santad/SNTApplication.m +++ b/Source/santad/SNTApplication.m @@ -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 @@ - (instancetype)init { 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,7 +90,6 @@ - (instancetype)init { // Listen for actionable config changes. NSKeyValueObservingOptions bits = (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld); - SNTConfigurator *configurator = [SNTConfigurator configurator]; [configurator addObserver:self forKeyPath:NSStringFromSelector(@selector(clientMode)) options:bits diff --git a/Source/santad/SNTDaemonControlController.m b/Source/santad/SNTDaemonControlController.m index 0ca6fc738..96eae6958 100644 --- a/Source/santad/SNTDaemonControlController.m +++ b/Source/santad/SNTDaemonControlController.m @@ -225,6 +225,7 @@ - (void)setBundleNotificationListener:(NSXPCListenerEndpoint *)listener { bs.remoteInterface = [SNTXPCBundleServiceInterface bundleServiceInterface]; [bs resume]; [[bs remoteObjectProxy] setBundleNotificationListener:listener]; + [bs invalidate]; } #pragma mark syncd Ops diff --git a/Source/santad/SNTExecutionController.m b/Source/santad/SNTExecutionController.m index 65269a00b..796fe1798 100644 --- a/Source/santad/SNTExecutionController.m +++ b/Source/santad/SNTExecutionController.m @@ -134,7 +134,7 @@ - (void)validateBinaryWithMessage:(santa_message_t)message { (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];