From d507e7950514547e2a33d5951ff87bbcf249a61b Mon Sep 17 00:00:00 2001 From: Russell Hancox Date: Fri, 19 Feb 2016 13:47:17 -0500 Subject: [PATCH] santad: Fix quarantine data collection. This previously didn't work for root (santactl fileinfo was fine) because quarantine data is per-user. --- Podfile | 5 +- Santa.xcodeproj/project.pbxproj | 2 - Source/common/SNTFileInfo.m | 88 +++++++++++++++++-- Source/common/SNTStoredEvent.m | 2 +- Source/santactl/fileinfo/SNTCommandFileInfo.m | 1 + 5 files changed, 84 insertions(+), 14 deletions(-) diff --git a/Podfile b/Podfile index 4e0ae0dc..bd47b581 100644 --- a/Podfile +++ b/Podfile @@ -2,14 +2,15 @@ platform :osx, "10.9" inhibit_all_warnings! -target :santactl do +target :Santa do pod 'MOLCertificate' pod 'MOLCodesignChecker' end -target :Santa do +target :santactl do pod 'MOLCertificate' pod 'MOLCodesignChecker' + pod 'FMDB' end target :santad do diff --git a/Santa.xcodeproj/project.pbxproj b/Santa.xcodeproj/project.pbxproj index 320803ba..fdba0bce 100644 --- a/Santa.xcodeproj/project.pbxproj +++ b/Santa.xcodeproj/project.pbxproj @@ -78,7 +78,6 @@ 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 */; }; - 0D54E0B11976F8D3000BB59F /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD6041190ACCB8006B445C /* SNTFileInfo.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 */; }; @@ -1323,7 +1322,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0D54E0B11976F8D3000BB59F /* SNTFileInfo.m in Sources */, 0DCA552718C95928002A7DAE /* SNTXPCConnection.m in Sources */, 0D385DF1180DE51600418BC6 /* SNTAppDelegate.m in Sources */, 0D88680A1AC48A1200B86659 /* SNTSystemInfo.m in Sources */, diff --git a/Source/common/SNTFileInfo.m b/Source/common/SNTFileInfo.m index 9ce7d623..dfc91546 100644 --- a/Source/common/SNTFileInfo.m +++ b/Source/common/SNTFileInfo.m @@ -18,7 +18,11 @@ #include #include +#include #include +#include + +#import // Simple class to hold the data of a mach_header and the offset within the file // in which that header was found. @@ -42,6 +46,7 @@ @property NSString *path; @property NSFileHandle *fileHandle; @property NSUInteger fileSize; +@property NSString *fileOwnerHomeDir; // Cached properties @property NSBundle *bundleRef; @@ -76,6 +81,13 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE; _fileSize = fileStat.st_size; if (_fileSize == 0) return nil; + + if (fileStat.st_uid != 0) { + struct passwd *pwd = getpwuid(fileStat.st_uid); + if (pwd) { + _fileOwnerHomeDir = @(pwd->pw_dir); + } + } } return self; @@ -307,21 +319,26 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE; #pragma mark Quarantine Data - (NSString *)quarantineDataURL { - NSURL *url = [self quarantineData][(__bridge NSString *)kLSQuarantineDataURLKey]; - return [url absoluteString]; + NSURL *dataURL = [self quarantineData][@"LSQuarantineDataURL"]; + if (dataURL == (NSURL *)[NSNull null]) dataURL = nil; + return [dataURL absoluteString]; } - (NSString *)quarantineRefererURL { - NSURL *url = [self quarantineData][(__bridge NSString *)kLSQuarantineOriginURLKey]; - return [url absoluteString]; + NSURL *originURL = [self quarantineData][@"LSQuarantineOriginURL"]; + if (originURL == (NSURL *)[NSNull null]) originURL = nil; + return [originURL absoluteString]; } - (NSString *)quarantineAgentBundleID { - return [self quarantineData][(__bridge NSString *)kLSQuarantineAgentBundleIdentifierKey]; + NSString *agentBundle = [self quarantineData][@"LSQuarantineAgentBundleIdentifier"]; + if (agentBundle == (NSString *)[NSNull null]) agentBundle = nil; + return agentBundle; } - (NSDate *)quarantineTimestamp { - return [self quarantineData][(__bridge NSString *)kLSQuarantineTimeStampKey]; + NSDate *timeStamp = [self quarantineData][@"LSQuarantineTimeStamp"]; + return timeStamp; } #pragma mark Internal Methods @@ -477,13 +494,66 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE; /// /// Retrieve quarantine data for a file and caches the dictionary +/// This method attempts to handle fetching the quarantine data even if the running user +/// is not the one who downloaded the file. /// - (NSDictionary *)quarantineData { - if (!self.quarantineDict && NSURLQuarantinePropertiesKey != NULL) { + if (!self.quarantineDict && self.fileOwnerHomeDir) { + self.quarantineDict = (NSDictionary *)[NSNull null]; + NSURL *url = [NSURL fileURLWithPath:self.path]; NSDictionary *d = [url resourceValuesForKeys:@[ NSURLQuarantinePropertiesKey ] error:NULL]; - self.quarantineDict = d[NSURLQuarantinePropertiesKey]; - if (!self.quarantineDict) self.quarantineDict = (NSDictionary *)[NSNull null]; + + if (d[NSURLQuarantinePropertiesKey]) { + d = d[NSURLQuarantinePropertiesKey]; + + if (d[@"LSQuarantineIsOwnedByCurrentUser"]) { + self.quarantineDict = d; + } else if (d[@"LSQuarantineEventIdentifier"]) { + NSMutableDictionary *quarantineDict = [d mutableCopy]; + + // If self.path is on a quarantine disk image, LSQuarantineDiskImageURL will point to the + // disk image and self.fileOwnerHomeDir will be incorrect (probably root). + NSString *fileOwnerHomeDir = self.fileOwnerHomeDir; + if (d[@"LSQuarantineDiskImageURL"]) { + struct stat fileStat; + stat([d[@"LSQuarantineDiskImageURL"] fileSystemRepresentation], &fileStat); + if (fileStat.st_uid != 0) { + struct passwd *pwd = getpwuid(fileStat.st_uid); + if (pwd) { + fileOwnerHomeDir = @(pwd->pw_dir); + } + } + } + + NSURL *dbPath = [NSURL fileURLWithPathComponents:@[ + fileOwnerHomeDir, @"Library", @"Preferences", + @"com.apple.LaunchServices.QuarantineEventsV2" ]]; + FMDatabase *db = [FMDatabase databaseWithPath:[dbPath absoluteString]]; + db.logsErrors = NO; + if ([db open]) { + FMResultSet *rs = [db executeQuery:@"SELECT * FROM LSQuarantineEvent " + @"WHERE LSQuarantineEventIdentifier=?", + d[@"LSQuarantineEventIdentifier"]]; + if ([rs next]) { + NSString *agentBundleID = [rs stringForColumn:@"LSQuarantineAgentBundleIdentifier"]; + NSString *dataURLString = [rs stringForColumn:@"LSQuarantineDataURLString"]; + NSString *originURLString = [rs stringForColumn:@"LSQuarantineOriginURLString"]; + double timeStamp = [rs doubleForColumn:@"LSQuarantineTimeStamp"]; + + quarantineDict[@"LSQuarantineAgentBundleIdentifier"] = agentBundleID; + quarantineDict[@"LSQuarantineDataURL"] = [NSURL URLWithString:dataURLString]; + quarantineDict[@"LSQuarantineOriginURL"] = [NSURL URLWithString:originURLString]; + quarantineDict[@"LSQuarantineTimestamp"] = + [NSDate dateWithTimeIntervalSinceReferenceDate:timeStamp]; + + self.quarantineDict = quarantineDict; + } + [rs close]; + [db close]; + } + } + } } return (self.quarantineDict == (NSDictionary *)[NSNull null]) ? nil : self.quarantineDict; } diff --git a/Source/common/SNTStoredEvent.m b/Source/common/SNTStoredEvent.m index 9b2f0e56..9eb33429 100644 --- a/Source/common/SNTStoredEvent.m +++ b/Source/common/SNTStoredEvent.m @@ -52,7 +52,7 @@ ENCODE(self.quarantineDataURL, @"quarantineDataURL"); ENCODE(self.quarantineRefererURL, @"quarantineRefererURL"); - ENCODE(self.quarantineTimestamp, @"quarantineTiemstamp"); + ENCODE(self.quarantineTimestamp, @"quarantineTimestamp"); ENCODE(self.quarantineAgentBundleID, @"quarantineAgentBundleID"); } diff --git a/Source/santactl/fileinfo/SNTCommandFileInfo.m b/Source/santactl/fileinfo/SNTCommandFileInfo.m index 847569e9..0a0c66cd 100644 --- a/Source/santactl/fileinfo/SNTCommandFileInfo.m +++ b/Source/santactl/fileinfo/SNTCommandFileInfo.m @@ -119,6 +119,7 @@ REGISTER_COMMAND_NAME(@"fileinfo") } + (void)printKey:(NSString *)key value:(NSString *)value { + if (!key || !value) return; printf("%-21s: %s\n", [key UTF8String], [value UTF8String]); }