Compare commits

...

14 Commits
0.8.7 ... 0.8.8

Author SHA1 Message Date
Russell Hancox
cf251c45b8 Project: Update package Makefile for santad/santactl move 2015-06-22 15:57:10 -04:00
Russell Hancox
385c03096d Project: Missed santactl/santad move in Rakefile dist command 2015-06-22 15:35:03 -04:00
Russell Hancox
f323f5e3de santad: Up watchdog interval to 60s and CPU threshold to 20%.
Whilst during normal operation santad doesn't use more than 5% CPU, it does spike if lots
of processes start, such as during bootup. This change helps to reduce the noise.
2015-06-22 15:28:02 -04:00
Russell Hancox
9562ee86cd Project: Add missing copy to a few properties previously missed 2015-06-19 17:32:45 -04:00
Russell Hancox
adfb4bc861 SNTFileInfo: Better caching of properties 2015-06-19 17:31:48 -04:00
Russell Hancox
957232ca40 santactl: Fix event counting bug in status command 2015-06-16 18:02:41 -04:00
Russell Hancox
44c9d9aead santad: Add watchdog thread to print warnings if CPU/RAM usage seem high. 2015-06-15 16:31:55 -04:00
Russell Hancox
f95245cedd 10.11 Prep: Move santad,santactl from /usr/libexec,/usr/sbin to within santa-driver.kext 2015-06-15 16:18:51 -04:00
Russell Hancox
3c034adf48 GUI: Prevent reconnection loop when XPC connection dies 2015-06-10 16:46:32 -04:00
Russell Hancox
abd3c5a06d GUI: Restore constraint move Dismiss button when event detail URL is not set 2015-06-10 16:45:16 -04:00
Russell Hancox
ca4951a475 SNTFileWatcher: Update test file location 2015-06-09 13:50:43 -04:00
Russell Hancox
e751a3d307 SNTFileWatcher: Only get the fileSystemRepresentation once, to avoid high memory use when file doesn't exist 2015-06-09 13:10:29 -04:00
Russell Hancox
2a8bdfd714 santad: Use _exit instead of exit after fork. Oops. 2015-06-01 17:12:12 -04:00
Russell Hancox
be9dca3ee2 GUI: Add close button to About window. 2015-05-21 16:12:48 -04:00
24 changed files with 297 additions and 181 deletions

View File

@@ -25,10 +25,8 @@ PACKAGE_VERSION:=$(shell curl -fs https://api.github.com/repos/google/santa/rele
# santa-$version.tar.bz2
# +--santa-$version
# |-- binaries
# | |-- santa-driver.kext
# | |-- Santa.app
# | |-- santad
# | +-- santactl
# | |-- santa-driver.kext
# | |-- Santa.app
# |-- conf
# | |-- install.sh
# | |-- com.google.santad.plist
@@ -36,15 +34,13 @@ PACKAGE_VERSION:=$(shell curl -fs https://api.github.com/repos/google/santa/rele
# | |-- com.google.santagui.plist
# | +-- com.google.santa.asl.conf
# +--dsym
# |-- santa-driver.kext.dSYM
# |-- Santa.app.dSYM
# |-- santad.dSYM
# +-- santactl.dSYM
# |-- santa-driver.kext.dSYM
# |-- Santa.app.dSYM
# |-- santad.dSYM
# +-- santactl.dSYM
PACKAGE_DOWNLOAD_URL:="https://github.com/google/santa/releases/download/${PACKAGE_VERSION}/santa-${PACKAGE_VERSION}.tar.bz2"
PAYLOAD:=pack-usr-libexec-santad \
pack-usr-sbin-santactl \
pack-Library-Extensions-santa-driver.kext \
PAYLOAD:=pack-Library-Extensions-santa-driver.kext \
pack-applications-Santa.app \
pack-Library-LaunchDaemons-com.google.santad.plist \
pack-Library-LaunchDaemons-com.google.santasync.plist \
@@ -53,8 +49,6 @@ PAYLOAD:=pack-usr-libexec-santad \
pack-script-preinstall \
pack-script-postinstall
santad: download
santactl: download
santa-driver.kext: download
Santa.app: download
com.google.santad.plist: download
@@ -68,12 +62,6 @@ download:
@curl -fL ${PACKAGE_DOWNLOAD_URL} | tar xvj --strip=2
@rm -rf *.dSYM
pack-usr-libexec-santad: santad l_usr
@sudo mkdir -p ${WORK_D}/usr/libexec
@sudo chown root:wheel ${WORK_D}/usr/libexec
@sudo chmod 755 ${WORK_D}/usr/libexec
@sudo install -m 755 -o root -g wheel santad ${WORK_D}/usr/libexec
pack-etc-asl-com.google.santa.asl.conf: com.google.santa.asl.conf l_private_etc
@sudo mkdir -p ${WORK_D}/private/etc/asl
@sudo chown root:wheel ${WORK_D}/private/etc/asl
@@ -92,8 +80,6 @@ myclean:
@rm -rf *.dSYM
@rm -rf Santa.app
@rm -rf santa-driver.kext
@rm -f santad
@rm -f santactl
@rm -f config.plist
@rm -f com.google.santa.asl.conf
@rm -f com.google.santad.plist

View File

@@ -18,6 +18,9 @@ sleep 1
sleep 1
# Create hopefully useful symlink for santactl
/bin/ln -s /Library/Extensions/santa-driver.kext/Contents/MacOS/santactl /usr/local/bin
user=$(/usr/bin/stat -f '%u' /dev/console)
[[ -z "$user" ]] && exit 0
/bin/launchctl asuser ${user} /bin/launchctl load /Library/LaunchAgents/com.google.santagui.plist

View File

@@ -13,6 +13,10 @@ sleep 1
/sbin/kextunload -b com.google.santa-driver >/dev/null 2>&1
# Remove files from old Santa install locations, if they still exist
/bin/rm /usr/libexec/santad
/bin/rm /usr/sbin/santactl
sleep 1
user=$(/usr/bin/stat -f '%u' /dev/console)

View File

@@ -6,14 +6,14 @@
<string>com.google.santad</string>
<key>ProgramArguments</key>
<array>
<string>/usr/libexec/santad</string>
<string>/Library/Extensions/santa-driver.kext/Contents/MacOS/santad</string>
</array>
<key>MachServices</key>
<dict>
<key>SantaXPCNotifications</key>
<true/>
<key>SantaXPCControl</key>
<true/>
<key>SantaXPCNotifications</key>
<true/>
<key>SantaXPCControl</key>
<true/>
</dict>
<key>StandardOutPath</key>
<string>/var/log/santa.log</string>

View File

@@ -6,8 +6,8 @@
<string>com.google.santasync</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/santactl</string>
<string>sync</string>
<string>/Library/Extensions/santa-driver.kext/Contents/MacOS/santactl</string>
<string>sync</string>
</array>
<key>StandardErrorPath</key>
<string>/var/log/santa.log</string>

View File

@@ -28,11 +28,14 @@ GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
[[ -n "$GUI_USER" ]] && \
/bin/launchctl asuser ${GUI_USER} /bin/launchctl remove /Library/LaunchAgents/com.google.santagui.plist
# Delete old files, if they still exist
/bin/rm /usr/libexec/santad
/bin/rm /usr/sbin/santactl
# Copy new files.
/bin/cp ${SOURCE}/binaries/santad /usr/libexec
/bin/cp ${SOURCE}/binaries/santactl /usr/sbin
/bin/cp -r ${SOURCE}/binaries/santa-driver.kext /Library/Extensions
/bin/cp -r ${SOURCE}/binaries/Santa.app /Applications
/bin/ln -s /Library/Extensions/santa-driver.kext/Contents/MacOS/santactl /usr/local/bin
/bin/cp ${SOURCE}/conf/com.google.{santad,santasync}.plist /Library/LaunchDaemons
/bin/cp ${SOURCE}/conf/com.google.santagui.plist /Library/LaunchAgents

View File

@@ -4,7 +4,7 @@ WORKSPACE = 'Santa.xcworkspace'
DEFAULT_SCHEME = 'All'
OUTPUT_PATH = 'Build'
DIST_PATH = 'Dist'
BINARIES = ['Santa.app', 'santa-driver.kext', 'santad', 'santactl']
BINARIES = ['Santa.app', 'santa-driver.kext']
XCPRETTY_DEFAULTS = '-sc'
XCODEBUILD_DEFAULTS = "-workspace #{WORKSPACE} -derivedDataPath #{OUTPUT_PATH} -parallelizeTargets"
@@ -33,10 +33,8 @@ task :init do
end
task :remove_existing do
system 'sudo rm -rf /santa-driver.kext'
system 'sudo rm -rf /Library/Extensions/santa-driver.kext'
system 'sudo rm -rf /Applications/Santa.app'
system 'sudo rm /usr/libexec/santad'
system 'sudo rm /usr/sbin/santactl'
end
desc "Clean"
@@ -88,10 +86,8 @@ namespace :install do
Rake::Task['build:build'].invoke(config)
puts "Installing with configuration: #{config}"
Rake::Task['remove_existing'].invoke()
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/santa-driver.kext /"
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/santa-driver.kext /Library/Extensions"
system "sudo cp -r #{OUTPUT_PATH}/Products/#{config}/Santa.app /Applications"
system "sudo cp #{OUTPUT_PATH}/Products/#{config}/santad /usr/libexec"
system "sudo cp #{OUTPUT_PATH}/Products/#{config}/santactl /usr/sbin"
end
end
@@ -169,7 +165,7 @@ end
task :load_kext do
puts "Loading kernel extension"
system "sudo kextload /santa-driver.kext"
system "sudo kextload /Library/Extensions/santa-driver.kext"
end
task :load_gui do

View File

@@ -118,6 +118,8 @@
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D870192160180078A5C0 /* SNTCommandSyncLogUpload.m */; };
0DC765EA1B28D9EA00BAE651 /* santad in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0D9A7F3D1759330500035EB5 /* santad */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
0DC765EB1B28D9EA00BAE651 /* santactl in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0D35BD9E18FD71CE00921A21 /* santactl */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
0DCD5FBF1909D64A006B445C /* SNTCommandBinaryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD5FBE1909D64A006B445C /* SNTCommandBinaryInfo.m */; };
0DCD6042190ACCB8006B445C /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.m */; };
@@ -203,8 +205,36 @@
remoteGlobalIDString = 0D9A7F3C1759330400035EB5;
remoteInfo = santad;
};
0DC765E51B28D9C600BAE651 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0D91BCA8174E8A6500131A7D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0D9A7F3C1759330400035EB5;
remoteInfo = santad;
};
0DC765E71B28D9C600BAE651 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0D91BCA8174E8A6500131A7D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0D35BD9D18FD71CE00921A21;
remoteInfo = santactl;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0DC765E91B28D9CB00BAE651 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 6;
files = (
0DC765EA1B28D9EA00BAE651 /* santad in CopyFiles */,
0DC765EB1B28D9EA00BAE651 /* santactl in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0A84545E322F475FA0B505D5 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
0D0016A2192BCD3C005E7FCD /* KernelTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KernelTests; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -835,10 +865,13 @@
0DD98E691A5DD5C900A754C6 /* Update Module Version */,
0D91BCAE174E8A7E00131A7D /* Sources */,
0D91BCB0174E8A7E00131A7D /* Headers */,
0DC765E91B28D9CB00BAE651 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
0DC765E61B28D9C600BAE651 /* PBXTargetDependency */,
0DC765E81B28D9C600BAE651 /* PBXTargetDependency */,
);
name = "santa-driver";
productName = "santa-driver";
@@ -1261,6 +1294,16 @@
target = 0D9A7F3C1759330400035EB5 /* santad */;
targetProxy = 0D9A7F591759393600035EB5 /* PBXContainerItemProxy */;
};
0DC765E61B28D9C600BAE651 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0D9A7F3C1759330400035EB5 /* santad */;
targetProxy = 0DC765E51B28D9C600BAE651 /* PBXContainerItemProxy */;
};
0DC765E81B28D9C600BAE651 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0D35BD9D18FD71CE00921A21 /* santactl */;
targetProxy = 0DC765E71B28D9C600BAE651 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
@@ -1293,6 +1336,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WARNING_CFLAGS = "";
@@ -1322,6 +1366,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WARNING_CFLAGS = "";
@@ -1456,6 +1501,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santactl-Info.plist";
INSTALL_PATH = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
@@ -1489,6 +1535,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santactl-Info.plist";
INSTALL_PATH = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
@@ -1622,6 +1669,7 @@
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -1660,6 +1708,7 @@
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREPROCESSOR_DEFINITIONS = "";
@@ -1725,7 +1774,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
INSTALL_PATH = /usr/sbin;
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -1753,7 +1802,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "${DERIVED_FILE_DIR}/santad-Info.plist";
INSTALL_PATH = /usr/sbin;
INSTALL_PATH = "";
LIBRARY_SEARCH_PATHS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14C1514" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14D136" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
@@ -14,7 +14,7 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Santa" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES"/>
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="200"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" id="se5-gp-TjO">
@@ -65,6 +65,9 @@ There are no user-configurable settings.</string>
<buttonCell key="cell" type="push" title="Dismiss" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uSw-o1-lWW">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="orderOut:" target="-1" id="6oW-zI-zn5"/>

View File

@@ -16,7 +16,7 @@
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="none" id="9Bq-yh-54f" customClass="SNTMessageWindow">
<windowStyleMask key="styleMask" utility="YES"/>
<rect key="contentRect" x="167" y="107" width="497" height="356"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1600"/>
<view key="contentView" id="Iwq-Lx-rLv">
<rect key="frame" x="0.0" y="0.0" width="497" height="356"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -155,7 +155,7 @@
<constraints>
<constraint firstAttribute="width" constant="1" id="0o1-Jh-epf"/>
</constraints>
<color key="borderColor" white="0.0" alpha="0.18" colorSpace="calibratedWhite"/>
<color key="borderColor" white="0.0" alpha="0.17999999999999999" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
@@ -234,6 +234,7 @@ DQ
</subviews>
<constraints>
<constraint firstItem="f1p-GL-O3o" firstAttribute="centerY" secondItem="eQb-0a-76J" secondAttribute="centerY" id="2Aq-1E-Ybz"/>
<constraint firstItem="BbV-3h-mmL" firstAttribute="leading" secondItem="Iwq-Lx-rLv" secondAttribute="leading" priority="500" constant="193" id="2uo-Cm-Tfp"/>
<constraint firstItem="h6f-PY-cc0" firstAttribute="top" secondItem="f1p-GL-O3o" secondAttribute="bottom" constant="8" id="496-VQ-Fx5"/>
<constraint firstItem="eQb-0a-76J" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="trailing" constant="-116" id="6Q5-Oo-1cI"/>
<constraint firstItem="BbV-3h-mmL" firstAttribute="top" secondItem="oFj-ol-xpL" secondAttribute="bottom" constant="35" id="7K6-bY-Rn6"/>
@@ -255,7 +256,6 @@ DQ
<constraint firstAttribute="centerX" secondItem="cD5-Su-lXR" secondAttribute="centerX" id="V0a-Py-iEc"/>
<constraint firstItem="oFj-ol-xpL" firstAttribute="leading" secondItem="lvJ-Rk-UT5" secondAttribute="leading" priority="999" id="Z6G-l9-G4a"/>
<constraint firstItem="oFj-ol-xpL" firstAttribute="top" secondItem="eQb-0a-76J" secondAttribute="bottom" constant="8" id="abm-cM-PN0"/>
<constraint firstAttribute="centerX" secondItem="BbV-3h-mmL" secondAttribute="centerX" priority="900" constant="-62.5" id="acs-5J-vQY"/>
<constraint firstItem="4Li-ul-zIi" firstAttribute="leading" secondItem="eQb-0a-76J" secondAttribute="trailing" constant="20" id="b0B-3w-grH"/>
<constraint firstItem="KEB-eH-x2Y" firstAttribute="leading" secondItem="oFj-ol-xpL" secondAttribute="leading" priority="999" id="b5A-M7-ZsD"/>
<constraint firstItem="KEB-eH-x2Y" firstAttribute="centerY" secondItem="PXc-xv-A28" secondAttribute="centerY" id="cHe-pZ-0Oq"/>

View File

@@ -70,8 +70,7 @@
self.listener.exportedInterface = [SNTXPCNotifierInterface notifierInterface];
self.listener.exportedObject = self.notificationManager;
self.listener.rejectedHandler = ^{
[weakSelf performSelectorInBackground:@selector(attemptReconnection)
withObject:nil];
[weakSelf attemptReconnection];
};
self.listener.invalidationHandler = self.listener.rejectedHandler;
[self.listener resume];

View File

@@ -37,7 +37,7 @@
///
/// The custom message to display for this event
///
@property NSString *customMessage;
@property(copy) NSString *customMessage;
///
/// The delegate to inform when the notification is dismissed

View File

@@ -65,4 +65,8 @@ typedef enum {
EVENTSTATE_MAX
} santa_eventstate_t;
static const char *kKextPath = "/Library/Extensions/santa-driver.kext";
static const char *kSantaDPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santad";
static const char *kSantaCtlPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santactl";
#endif // SANTA__COMMON__COMMONENUMS_H

View File

@@ -23,44 +23,23 @@
@interface SNTFileInfo ()
@property NSString *path;
@property NSData *fileData;
// Cached properties
@property NSData *firstMachHeaderData;
@property NSBundle *bundleRef;
@property NSDictionary *infoDict;
@property NSArray *architecturesArray;
@end
@implementation SNTFileInfo
- (instancetype)initWithPath:(NSString *)path {
self = [super init];
if (self) {
// Convert to absolute, standardized path
path = [path stringByResolvingSymlinksInPath];
if (![path isAbsolutePath]) {
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
path = [cwd stringByAppendingPathComponent:path];
}
path = [path stringByStandardizingPath];
// Determine if file exists.
// If path is actually a directory, check to see if it's a bundle and has a CFBundleExecutable.
BOOL directory;
if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&directory]) {
return nil;
} else if (directory) {
NSString *infoPath = [path stringByAppendingPathComponent:@"Contents/Info.plist"];
NSDictionary *d = [NSDictionary dictionaryWithContentsOfFile:infoPath];
if (d && d[@"CFBundleExecutable"]) {
path = [path stringByAppendingPathComponent:@"Contents/MacOS"];
_path = [path stringByAppendingPathComponent:d[@"CFBundleExecutable"]];
} else {
return nil;
}
} else {
_path = path;
}
_path = [self resolvePath:path];
if (!_path) return nil;
_fileData = [NSData dataWithContentsOfFile:_path options:NSDataReadingMappedIfSafe error:nil];
if (!_fileData) return nil;
if (_fileData.length == 0) return nil;
}
return self;
@@ -68,7 +47,7 @@
- (NSString *)SHA1 {
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
CC_SHA1([self.fileData bytes], (unsigned int)[self.fileData length], sha1);
CC_SHA1(self.fileData.bytes, (unsigned int)self.fileData.length, sha1);
// Convert the binary SHA into hex
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
@@ -80,12 +59,12 @@
}
- (NSString *)SHA256 {
unsigned char sha2[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha2);
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha256);
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[buf appendFormat:@"%02x", (unsigned char)sha2[i]];
[buf appendFormat:@"%02x", (unsigned char)sha256[i]];
}
return buf;
@@ -101,42 +80,45 @@
}
- (NSArray *)architectures {
if (![self isMachO]) return nil;
if (!self.architecturesArray) {
self.architecturesArray = (NSArray *)[NSNull null];
if ([self isFat]) {
NSMutableArray *ret = [[NSMutableArray alloc] init];
if ([self isFat]) {
NSMutableArray *ret = [[NSMutableArray alloc] init];
// Retrieve just the fat_header, if possible.
NSData *head = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct fat_header))];
if (!head) return nil;
struct fat_header *fat_header = (struct fat_header *)[head bytes];
// Retrieve just the fat_header, if possible.
NSData *head = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct fat_header))];
if (!head) return nil;
struct fat_header *fat_header = (struct fat_header *)[head bytes];
// Get number of architectures in the binary
uint32_t narch = NSSwapBigIntToHost(fat_header->nfat_arch);
// Get number of architectures in the binary
uint32_t narch = NSSwapBigIntToHost(fat_header->nfat_arch);
// Retrieve just the fat_arch's, make a mutable copy and if necessary swap the bytes
NSData *archs = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
sizeof(struct fat_arch) * narch)];
if (!archs) return nil;
struct fat_arch *fat_archs = (struct fat_arch *)[archs bytes];
// Retrieve just the fat_arch's, make a mutable copy and if necessary swap the bytes
NSData *archs = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
sizeof(struct fat_arch) * narch)];
if (!archs) return nil;
struct fat_arch *fat_archs = (struct fat_arch *)[archs bytes];
// For each arch, get the name of it's architecture
for (uint32_t i = 0; i < narch; ++i) {
cpu_type_t cpu = (cpu_type_t)NSSwapBigIntToHost((unsigned int)fat_archs[i].cputype);
[ret addObject:[self nameForCPUType:cpu]];
// For each arch, get the name of its architecture
for (uint32_t i = 0; i < narch; ++i) {
cpu_type_t cpu = (cpu_type_t)NSSwapBigIntToHost((unsigned int)fat_archs[i].cputype);
[ret addObject:[self nameForCPUType:cpu]];
}
self.architecturesArray = ret;
} else if ([self firstMachHeader]) {
struct mach_header *hdr = [self firstMachHeader];
self.architecturesArray = @[ [self nameForCPUType:hdr->cputype] ];
}
return ret;
} else {
struct mach_header *hdr = [self firstMachHeader];
return @[ [self nameForCPUType:hdr->cputype] ];
}
return nil;
return self.architecturesArray == (NSArray *)[NSNull null] ? nil : self.architecturesArray;
}
- (BOOL)isDylib {
struct mach_header *mach_header = [self firstMachHeader];
if (!mach_header) return NO;
if (mach_header->filetype == MH_DYLIB || mach_header->filetype == MH_FVMLIB) {
if (mach_header && (mach_header->filetype == MH_DYLIB || mach_header->filetype == MH_FVMLIB)) {
return YES;
}
@@ -145,8 +127,7 @@
- (BOOL)isKext {
struct mach_header *mach_header = [self firstMachHeader];
if (!mach_header) return NO;
if (mach_header->filetype == MH_KEXT_BUNDLE) {
if (mach_header && mach_header->filetype == MH_KEXT_BUNDLE) {
return YES;
}
@@ -154,8 +135,7 @@
}
- (BOOL)isMachO {
return ([self.fileData length] >= 160 &&
([self isMachHeader:(struct mach_header *)[self.fileData bytes]] || [self isFat]));
return [self firstMachHeader] != nil;
}
- (BOOL)isFat {
@@ -163,8 +143,6 @@
}
- (BOOL)isScript {
if ([self.fileData length] < 1) return NO;
char magic[2];
[self.fileData getBytes:&magic length:2];
@@ -206,21 +184,19 @@
/// NSBundle reference for Bundle.app.
///
- (NSBundle *)bundle {
if (self.bundleRef) return self.bundleRef;
if (!self.bundleRef) {
self.bundleRef = (NSBundle *)[NSNull null];
NSArray *pathComponents = [self.path pathComponents];
// Check that the full path is at least 4-levels deep:
// e.g: /Calendar.app/Contents/MacOS/Calendar
NSArray *pathComponents = [self.path pathComponents];
if ([pathComponents count] < 4) return nil;
// Check that the full path is at least 4-levels deep:
// e.g: /Calendar.app/Contents/MacOS/Calendar
if ([pathComponents count] < 4) return nil;
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 3)];
self.bundleRef = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
// Clear the bundle if it doesn't have a bundle ID
if (![self.bundleRef objectForInfoDictionaryKey:@"CFBundleIdentifier"]) self.bundleRef = nil;
return self.bundleRef;
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 3)];
NSBundle *bndl = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
if (bndl && [bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) self.bundleRef = bndl;
}
return self.bundleRef == (NSBundle *)[NSNull null] ? nil : self.bundleRef;
}
- (NSString *)bundlePath {
@@ -228,33 +204,37 @@
}
- (NSDictionary *)infoPlist {
if (self.infoDict) return self.infoDict;
if (!self.infoDict) {
self.infoDict = (NSDictionary *)[NSNull null];
if ([self bundle]) {
self.infoDict = [[self bundle] infoDictionary];
return self.infoDict;
}
NSURL *url = [NSURL fileURLWithPath:self.path isDirectory:NO];
self.infoDict =
if ([self bundle] && [self.bundle infoDictionary]) {
self.infoDict = [self.bundle infoDictionary];
} else {
// Binaries with embedded Info.plist aren't in an NSBundle but
// CFBundleCopyInfoDictionaryForURL will return the embedded info dict.
NSURL *url = [NSURL fileURLWithPath:self.path isDirectory:NO];
NSDictionary *infoDict =
(__bridge_transfer NSDictionary *)CFBundleCopyInfoDictionaryForURL((__bridge CFURLRef)url);
return self.infoDict;
if (infoDict) self.infoDict = infoDict;
}
}
return self.infoDict == (NSDictionary *)[NSNull null] ? nil : self.infoDict;
}
- (NSString *)bundleIdentifier {
return [[self infoPlist] objectForKey:@"CFBundleIdentifier"];
return [self.infoPlist objectForKey:@"CFBundleIdentifier"];
}
- (NSString *)bundleName {
return [[self infoPlist] objectForKey:@"CFBundleName"];
return [self.infoPlist objectForKey:@"CFBundleName"];
}
- (NSString *)bundleVersion {
return [[self infoPlist] objectForKey:@"CFBundleVersion"];
return [self.infoPlist objectForKey:@"CFBundleVersion"];
}
- (NSString *)bundleShortVersionString {
return [[self infoPlist] objectForKey:@"CFBundleShortVersionString"];
return [self.infoPlist objectForKey:@"CFBundleShortVersionString"];
}
- (NSArray *)downloadURLs {
@@ -290,30 +270,31 @@
/// architecture-specific header.
///
- (struct mach_header *)firstMachHeader {
if (![self isMachO]) return NULL;
if (!self.firstMachHeaderData) {
self.firstMachHeaderData = (NSData *)[NSNull null];
struct mach_header *mach_header = (struct mach_header *)[self.fileData bytes];
struct fat_header *fat_header = (struct fat_header *)[self.fileData bytes];
if ([self isFatHeader:(struct fat_header *)[self.fileData bytes]]) {
// Get the bytes for the fat_arch
NSData *archHdr = [self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header),
sizeof(struct fat_arch))];
if (!archHdr) return NULL;
struct fat_arch *fat_arch = (struct fat_arch *)[archHdr bytes];
if ([self isFatHeader:fat_header]) {
// Get the bytes for the fat_arch
NSData *archHdr =
[self safeSubdataWithRange:NSMakeRange(sizeof(struct fat_header), sizeof(struct fat_arch))];
if (!archHdr) return nil;
struct fat_arch *fat_arch = (struct fat_arch *)[archHdr bytes];
// Get bytes for first mach_header
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(NSSwapBigIntToHost(fat_arch->offset),
sizeof(struct mach_header))];
if (!machHdr || ![self isMachHeader:(struct mach_header *)machHdr.bytes]) return NULL;
// Get bytes for first mach_header
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(NSSwapBigIntToHost(fat_arch->offset),
sizeof(struct mach_header))];
if (!machHdr) return nil;
mach_header = (struct mach_header *)[machHdr bytes];
self.firstMachHeaderData = [machHdr copy];
} else if ([self isMachHeader:(struct mach_header *)[self.fileData bytes]]) {
NSData *machHdr = [self safeSubdataWithRange:NSMakeRange(0, sizeof(struct mach_header))];
if (!machHdr) return NULL;
self.firstMachHeaderData = [machHdr copy];
}
}
if ([self isMachHeader:mach_header]) {
return mach_header;
}
return NULL;
return (self.firstMachHeaderData == (NSData *)[NSNull null] ?
NULL :
(struct mach_header *)self.firstMachHeaderData.bytes);
}
- (BOOL)isMachHeader:(struct mach_header *)header {
@@ -354,4 +335,32 @@
return nil;
}
- (NSString *)resolvePath:(NSString *)path {
// Convert to absolute, standardized path
path = [path stringByResolvingSymlinksInPath];
if (![path isAbsolutePath]) {
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
path = [cwd stringByAppendingPathComponent:path];
}
path = [path stringByStandardizingPath];
// Determine if file exists.
// If path is actually a directory, check to see if it's a bundle and has a CFBundleExecutable.
BOOL directory;
if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&directory]) {
return nil;
} else if (directory) {
NSString *infoPath = [path stringByAppendingPathComponent:@"Contents/Info.plist"];
NSDictionary *d = [NSDictionary dictionaryWithContentsOfFile:infoPath];
if (d && d[@"CFBundleExecutable"]) {
path = [path stringByAppendingPathComponent:@"Contents/MacOS"];
return [path stringByAppendingPathComponent:d[@"CFBundleExecutable"]];
} else {
return nil;
}
} else {
return path;
}
}
@end

View File

@@ -70,7 +70,8 @@
close(fd);
}
while ((fd = open([weakSelf.filePath fileSystemRepresentation], O_EVTONLY)) < 0) {
const char *filePathCString = [weakSelf.filePath fileSystemRepresentation];
while ((fd = open(filePathCString, O_EVTONLY)) < 0) {
usleep(1000);
}

View File

@@ -22,7 +22,7 @@
///
/// The hash of the object this rule is for
///
@property NSString *shasum;
@property(copy) NSString *shasum;
///
/// The state of this rule
@@ -37,7 +37,7 @@
///
/// A custom message that will be displayed if this rule blocks a binary from executing
///
@property NSString *customMsg;
@property(copy) NSString *customMsg;
///
/// Designated initializer.

View File

@@ -67,7 +67,7 @@ REGISTER_COMMAND_NAME(@"status")
printf(" %-25s | %lld\n", "Kernel cache count", cacheCount);
// Database counts
__block int64_t eventCount = 1, binaryRuleCount = -1, certRuleCount = -1;
__block int64_t eventCount = -1, binaryRuleCount = -1, certRuleCount = -1;
[[daemonConn remoteObjectProxy] databaseRuleCounts:^(int64_t binary, int64_t certificate) {
binaryRuleCount = binary;
certRuleCount = certificate;

View File

@@ -27,7 +27,7 @@
/// If set, this is the user-agent to send with requests, otherwise remains the default
/// CFNetwork-based name.
///
@property(nonatomic) NSString *userAgent;
@property(copy, nonatomic) NSString *userAgent;
///
/// If set to YES, this session refuses redirect requests. Defaults to NO.
@@ -38,24 +38,24 @@
/// If set, the server that we connect to _must_ match this string. Redirects to other
/// hosts will not be allowed.
///
@property(nonatomic) NSString *serverHostname;
@property(copy, nonatomic) NSString *serverHostname;
///
/// This should be PEM data containing one or more certificates to use to verify the server's
/// certificate chain. This will override the trusted roots in the System Roots.
///
@property(nonatomic) NSData *serverRootsPemData;
@property(copy, nonatomic) NSData *serverRootsPemData;
///
/// If set and client certificate authentication is needed, the pkcs#12 file will be loaded
///
@property(nonatomic) NSString *clientCertFile;
@property(copy, nonatomic) NSString *clientCertFile;
///
/// If set and client certificate authentication is needed, the password being used for
/// loading the clientCertFile
///
@property(nonatomic) NSString *clientCertPassword;
@property(copy, nonatomic) NSString *clientCertPassword;
///
/// If set and client certificate authentication is needed, will search the keychain for a
@@ -65,7 +65,7 @@
/// @note If this property is not set and neither is |clientCertIssuerCn|, the allowed issuers
/// provided by the server will be used to find a matching certificate.
///
@property(nonatomic) NSString *clientCertCommonName;
@property(copy, nonatomic) NSString *clientCertCommonName;
///
/// If set and client certificate authentication is needed, will search the keychain for a
@@ -76,7 +76,7 @@
/// @note If this property is not set and neither is |clientCertCommonName|, the allowed issuers
/// provided by the server will be used to find a matching certificate.
///
@property(nonatomic) NSString *clientCertIssuerCn;
@property(copy, nonatomic) NSString *clientCertIssuerCn;
/// Designated initializer
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration;

View File

@@ -20,8 +20,8 @@
@property NSURL *syncBaseURL;
/// Machine identifier and owner
@property NSString *machineID;
@property NSString *machineOwner;
@property(copy) NSString *machineID;
@property(copy) NSString *machineOwner;
/// Clean sync flag, sent from server. If True, all existing rules
/// should be deleted before inserting any new rules.

View File

@@ -16,6 +16,7 @@
#include <IOKit/kext/KextManager.h>
#import "SNTCommonEnums.h"
#import "SNTFileInfo.h"
#import "SNTKernelCommon.h"
#import "SNTXPCConnection.h"
@@ -61,8 +62,7 @@ REGISTER_COMMAND_NAME(@"version")
return loadedKexts[@(USERCLIENT_ID)][@"CFBundleVersion"];
}
SNTFileInfo *driverInfo =
[[SNTFileInfo alloc] initWithPath:@"/Library/Extensions/santa-driver.kext"];
SNTFileInfo *driverInfo = [[SNTFileInfo alloc] initWithPath:@(kKextPath)];
if (driverInfo) {
return [driverInfo.bundleVersion stringByAppendingString:@" (unloaded)"];
}
@@ -71,13 +71,13 @@ REGISTER_COMMAND_NAME(@"version")
}
+ (NSString *)santadVersion {
SNTFileInfo *daemonInfo = [[SNTFileInfo alloc] initWithPath:@"/usr/libexec/santad"];
SNTFileInfo *daemonInfo = [[SNTFileInfo alloc] initWithPath:@(kSantaDPath)];
return daemonInfo.bundleVersion;
}
+ (NSString *)santaAppVersion {
SNTFileInfo *guiInfo =
[[SNTFileInfo alloc] initWithPath:@"/Applications/Santa.app/Contents/MacOS/Santa"];
[[SNTFileInfo alloc] initWithPath:@"/Applications/Santa.app/Contents/MacOS/Santa"];
return guiInfo.bundleVersion;
}

View File

@@ -21,6 +21,7 @@
#import "SNTCertificate.h"
#import "SNTCodesignChecker.h"
#import "SNTCommonEnums.h"
#import "SNTConfigurator.h"
#import "SNTDriverManager.h"
#import "SNTDropRootPrivs.h"
@@ -141,9 +142,9 @@
if (respondedAction == ACTION_RESPOND_CHECKBW_DENY) {
// So the server has something to show the user straight away, initiate an event
// upload for the blocked binary rather than waiting for the next sync.
// The event upload is skipped if the full path is equal to that of /usr/sbin/santactl so that
// The event upload is skipped if the full path is equal to that of santactl so that
/// on the off chance that santactl is not whitelisted, we don't get into an infinite loop.
if (![path isEqual:@"/usr/sbin/santactl"]) {
if (![path isEqual:@(kSantaCtlPath)]) {
[self initiateEventUploadForSHA256:sha256];
}
@@ -266,11 +267,10 @@
// Ensure we have no privileges
if (!DropRootPrivileges()) {
exit(1);
_exit(1);
}
exit(execl("/usr/sbin/santactl", "/usr/sbin/santactl", "sync",
"singleevent", [sha256 UTF8String], NULL));
_exit(execl(kSantaCtlPath, kSantaCtlPath, "sync", "singleevent", [sha256 UTF8String], NULL));
}
}

View File

@@ -14,8 +14,63 @@
#include "SNTLogging.h"
#include <pthread/pthread.h>
#include <sys/resource.h>
#import "SNTApplication.h"
/// Converts a timeval struct to double, converting the microseconds value to seconds.
static inline double timeval_to_double(struct timeval tv) {
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
/// The watchdog thread function, used to monitor santad CPU/RAM usage and print a warning
/// if it goes over certain thresholds.
void *watchdog_thread_f(__unused void *idata) {
pthread_setname_np("Watchdog");
// Number of seconds to wait between checks.
const int timeInterval = 60;
// Amount of CPU usage to trigger warning, as a percentage averaged over timeInterval
// santad's usual CPU usage is 0-3% but can occasionally spike if lots of processes start at once.
const int cpuWarnThreshold = 20;
// Amount of RAM usage to trigger warning, in MB.
// santad's usual RAM usage is between 5-50MB but can spike if lots of processes start at once.
const int memWarnThreshold = 100;
struct rusage usage;
static double prev_total_time = 0.0;
struct mach_task_basic_info t_info;
mach_msg_type_number_t t_info_count = MACH_TASK_BASIC_INFO_COUNT;
while(true) {
sleep(timeInterval);
// CPU
getrusage(RUSAGE_SELF, &usage);
double total_time = timeval_to_double(usage.ru_utime) + timeval_to_double(usage.ru_stime);
double percentage = (((total_time - prev_total_time) / (double)timeInterval) * 100.0);
prev_total_time = total_time;
if (percentage > cpuWarnThreshold) {
LOGW(@"Watchdog: potentially high CPU use, ~%.2f%% over last %d seconds.",
percentage, timeInterval);
}
// RAM
if (KERN_SUCCESS == task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
(task_info_t)&t_info, &t_info_count)) {
double ramUseMb = (double) t_info.resident_size / 1024 / 1024;
if (ramUseMb > (double)memWarnThreshold) {
LOGW(@"Watchdog: potentially high RAM use, RSS is %.2fMB.", ramUseMb);
}
}
}
return NULL;
}
int main(int argc, const char *argv[]) {
@autoreleasepool {
// Do not buffer stdout
@@ -33,6 +88,10 @@ int main(int argc, const char *argv[]) {
SNTApplication *s = [[SNTApplication alloc] init];
[s performSelectorInBackground:@selector(run) withObject:nil];
// Create watchdog thread
pthread_t watchdog_thread;
pthread_create(&watchdog_thread, NULL, watchdog_thread_f, NULL);
[[NSRunLoop mainRunLoop] run];
}
}

View File

@@ -26,7 +26,7 @@
XCTAssertNotNil(sut);
XCTAssertEqualObjects(sut.path, @"/Applications/Safari.app/Contents/MacOS/Safari");
sut = [[SNTFileInfo alloc] initWithPath:@"../../../../../../../../../bin/ls"];
sut = [[SNTFileInfo alloc] initWithPath:@"../../../../../../../../../../../../../../../bin/ls"];
XCTAssertEqualObjects(sut.path, @"/bin/ls");
sut = [[SNTFileInfo alloc] initWithPath:@"/usr/bin/qlmanage"];

View File

@@ -27,7 +27,7 @@
[super setUp];
self.fm = [NSFileManager defaultManager];
self.file = @"/tmp/SNTFileWatcherTest_File";
self.file = [NSTemporaryDirectory() stringByAppendingString:@"SNTFileWatcherTest_File"];
[self createFile];
usleep(10000);
}