[AltServer] Refactors Mail plug-in installation to fix notarization errors

AltServer must now download the Mail plug-in at runtime, because notarization will fail if AltServer contains an unsigned binary (and as of Catalina, Mail plug-ins only work if they’re unsigned)
This commit is contained in:
Riley Testut
2020-02-13 21:41:31 -08:00
parent 891da58cfd
commit 07efd681c1
19 changed files with 870 additions and 690 deletions

View File

@@ -72,7 +72,7 @@ NSErrorDomain const AltServerInstallationErrorDomain = @"com.rileytestut.AltServ
return NSLocalizedString(@"Invalid anisette data.", @""); return NSLocalizedString(@"Invalid anisette data.", @"");
case ALTServerErrorPluginNotFound: case ALTServerErrorPluginNotFound:
return NSLocalizedString(@"Could not connect to Mail plug-in. Please make sure the plug-in is installed and Mail is running, then try again.", @""); return NSLocalizedString(@"Could not connect to Mail plug-in. Please make sure Mail is running and that you've enabled the plug-in in Mail's preferences, then try again.", @"");
} }
} }

Binary file not shown.

View File

@@ -14,24 +14,27 @@ import AltSign
import LaunchAtLogin import LaunchAtLogin
import STPrivilegedTask import STPrivilegedTask
private let pluginDirectoryURL = URL(fileURLWithPath: "/Library/Mail/Bundles", isDirectory: true)
private let pluginURL = pluginDirectoryURL.appendingPathComponent("AltPlugin.mailbundle")
enum PluginError: LocalizedError enum PluginError: LocalizedError
{ {
case installationScriptNotFound case cancelled
case failedToRun(Int) case unknown
case scriptError(String) case taskError(String)
case taskErrorCode(Int)
var errorDescription: String? { var errorDescription: String? {
switch self switch self
{ {
case .installationScriptNotFound: return NSLocalizedString("The installation script could not be found.", comment: "") case .cancelled: return NSLocalizedString("Mail plug-in installation was cancelled.", comment: "")
case .failedToRun(let errorCode): return String(format: NSLocalizedString("The installation script could not be run. (%@)", comment: ""), NSNumber(value: errorCode)) case .unknown: return NSLocalizedString("Failed to install Mail plug-in.", comment: "")
case .scriptError(let output): return output case .taskError(let output): return output
case .taskErrorCode(let errorCode): return String(format: NSLocalizedString("There was an error installing the Mail plug-in. (Error Code: %@)", comment: ""), NSNumber(value: errorCode))
} }
} }
} }
private let pluginURL = URL(fileURLWithPath: "/Library/Mail/Bundles/AltPlugin.mailbundle")
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
@@ -108,7 +111,7 @@ private extension AppDelegate
self.launchAtLoginMenuItem.state = LaunchAtLogin.isEnabled ? .on : .off self.launchAtLoginMenuItem.state = LaunchAtLogin.isEnabled ? .on : .off
self.launchAtLoginMenuItem.action = #selector(AppDelegate.toggleLaunchAtLogin(_:)) self.launchAtLoginMenuItem.action = #selector(AppDelegate.toggleLaunchAtLogin(_:))
if FileManager.default.fileExists(atPath: pluginURL.path) if self.isMailPluginInstalled
{ {
self.installMailPluginMenuItem.title = NSLocalizedString("Uninstall Mail Plug-in", comment: "") self.installMailPluginMenuItem.title = NSLocalizedString("Uninstall Mail Plug-in", comment: "")
} }
@@ -182,47 +185,73 @@ private extension AppDelegate
let device = self.connectedDevices[index] let device = self.connectedDevices[index]
if !self.isMailPluginInstalled func install()
{ {
let result = self.installMailPlugin() ALTDeviceManager.shared.installAltStore(to: device, appleID: username, password: password) { (result) in
guard result else { return } switch result
{
case .success:
let content = UNMutableNotificationContent()
content.title = NSLocalizedString("Installation Succeeded", comment: "")
content.body = String(format: NSLocalizedString("AltStore was successfully installed on %@.", comment: ""), device.name)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request)
case .failure(InstallError.cancelled), .failure(ALTAppleAPIError.requiresTwoFactorAuthentication):
// Ignore
break
case .failure(let error as NSError):
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = NSLocalizedString("Installation Failed", comment: "")
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? Error
{
alert.informativeText = underlyingError.localizedDescription
}
else
{
alert.informativeText = error.localizedDescription
}
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
alert.runModal()
}
}
} }
ALTDeviceManager.shared.installAltStore(to: device, appleID: username, password: password) { (result) in if !self.isMailPluginInstalled
switch result {
{ self.installMailPlugin { (result) in
case .success: DispatchQueue.main.async {
let content = UNMutableNotificationContent() switch result
content.title = NSLocalizedString("Installation Succeeded", comment: "") {
content.body = String(format: NSLocalizedString("AltStore was successfully installed on %@.", comment: ""), device.name) case .failure(PluginError.cancelled): break
case .failure(let error):
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) let alert = NSAlert()
UNUserNotificationCenter.current().add(request) alert.messageText = NSLocalizedString("Failed to Install Mail Plug-in", comment: "")
alert.informativeText = error.localizedDescription
case .failure(InstallError.cancelled), .failure(ALTAppleAPIError.requiresTwoFactorAuthentication): alert.runModal()
// Ignore
break case .success:
let alert = NSAlert()
case .failure(let error as NSError): alert.messageText = NSLocalizedString("Mail Plug-in Installed", comment: "")
alert.informativeText = NSLocalizedString("Please restart Mail and enable AltPlugin in Mail's Preferences. Mail must be running when installing or refreshing apps with AltServer.", comment: "")
let alert = NSAlert() alert.runModal()
alert.alertStyle = .critical
alert.messageText = NSLocalizedString("Installation Failed", comment: "") install()
}
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? Error
{
alert.informativeText = underlyingError.localizedDescription
} }
else
{
alert.informativeText = error.localizedDescription
}
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
alert.runModal()
} }
} }
else
{
install()
}
} }
@objc func toggleLaunchAtLogin(_ item: NSMenuItem) @objc func toggleLaunchAtLogin(_ item: NSMenuItem)
@@ -241,71 +270,205 @@ private extension AppDelegate
@objc func handleInstallMailPluginMenuItem(_ item: NSMenuItem) @objc func handleInstallMailPluginMenuItem(_ item: NSMenuItem)
{ {
installMailPlugin() if self.isMailPluginInstalled
{
self.uninstallMailPlugin { (result) in
DispatchQueue.main.async {
switch result
{
case .failure(PluginError.cancelled): break
case .failure(let error):
let alert = NSAlert()
alert.messageText = NSLocalizedString("Failed to Uninstall Mail Plug-in", comment: "")
alert.informativeText = error.localizedDescription
alert.runModal()
case .success:
let alert = NSAlert()
alert.messageText = NSLocalizedString("Mail Plug-in Uninstalled", comment: "")
alert.informativeText = NSLocalizedString("Please restart Mail for changes to take effect. You will not be able to use AltServer until the plug-in is reinstalled.", comment: "")
alert.runModal()
}
}
}
}
else
{
self.installMailPlugin { (result) in
DispatchQueue.main.async {
switch result
{
case .failure(PluginError.cancelled): break
case .failure(let error):
let alert = NSAlert()
alert.messageText = NSLocalizedString("Failed to Install Mail Plug-in", comment: "")
alert.informativeText = error.localizedDescription
alert.runModal()
case .success:
let alert = NSAlert()
alert.messageText = NSLocalizedString("Mail Plug-in Installed", comment: "")
alert.informativeText = NSLocalizedString("Please restart Mail and enable AltPlugin in Mail's Preferences. Mail must be running when installing or refreshing apps with AltServer.", comment: "")
alert.runModal()
}
}
}
}
} }
@discardableResult func installMailPlugin(completionHandler: @escaping (Result<Void, Error>) -> Void)
func installMailPlugin() -> Bool
{ {
do do
{ {
let previouslyInstalled = self.isMailPluginInstalled let alert = NSAlert()
alert.messageText = NSLocalizedString("Install Mail Plug-in", comment: "")
alert.informativeText = NSLocalizedString("AltServer requires a Mail plug-in in order to retrieve necessary information about your Apple ID. Would you like to install it now?", comment: "")
if !previouslyInstalled alert.addButton(withTitle: NSLocalizedString("Install Plug-in", comment: ""))
{ alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
let alert = NSAlert()
alert.messageText = NSLocalizedString("Install Mail Plug-in", comment: "") NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
alert.informativeText = NSLocalizedString("AltServer requires a Mail plug-in in order to retrieve necessary information about your Apple ID. Would you like to install it now?", comment: "")
let response = alert.runModal()
alert.addButton(withTitle: NSLocalizedString("Install Plug-in", comment: "")) guard response == .alertFirstButtonReturn else { throw PluginError.cancelled }
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
self.downloadPlugin { (result) in
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps) do
{
let response = alert.runModal() let fileURL = try result.get()
guard response == .alertFirstButtonReturn else { return false } defer { try? FileManager.default.removeItem(at: fileURL) }
// Unzip AltPlugin to plug-ins directory.
let authorization = try self.runAndKeepAuthorization("unzip", arguments: ["-o", fileURL.path, "-d", pluginDirectoryURL.path])
guard self.isMailPluginInstalled else { throw PluginError.unknown }
// Enable Mail plug-in preferences.
try self.run("defaults", arguments: ["write", "/Library/Preferences/com.apple.mail", "EnableBundles", "-bool", "YES"], authorization: authorization)
print("Finished installing Mail plug-in!")
completionHandler(.success(()))
}
catch
{
completionHandler(.failure(error))
}
} }
guard let scriptURL = Bundle.main.url(forResource: self.isMailPluginInstalled ? "UninstallPlugin" : "InstallPlugin", withExtension: "sh") else { throw PluginError.installationScriptNotFound }
try FileManager.default.setAttributes([.posixPermissions: 0o777], ofItemAtPath: scriptURL.path)
let task = STPrivilegedTask()
task.setLaunchPath(scriptURL.path)
task.setCurrentDirectoryPath(scriptURL.deletingLastPathComponent().path)
let errorCode = task.launch()
guard errorCode == 0 else { throw PluginError.failedToRun(Int(errorCode)) }
task.waitUntilExit()
if
let outputData = task.outputFileHandle()?.readDataToEndOfFile(),
let outputString = String(data: outputData, encoding: .utf8), !outputString.isEmpty
{
throw PluginError.scriptError(outputString)
}
if !previouslyInstalled && self.isMailPluginInstalled
{
let alert = NSAlert()
alert.messageText = NSLocalizedString("Mail Plug-in Installed", comment: "")
alert.informativeText = NSLocalizedString("Please restart Mail and enable AltPlugin in Mail's Preferences. Mail must be running when installing or refreshing apps with AltServer.", comment: "")
alert.runModal()
}
return true
} }
catch catch
{ {
let alert = NSAlert() completionHandler(.failure(PluginError.cancelled))
alert.messageText = self.isMailPluginInstalled ? NSLocalizedString("Failed to Uninstall Mail Plug-in", comment: "") : NSLocalizedString("Failed to Install Mail Plug-in", comment: "")
alert.informativeText = error.localizedDescription
alert.runModal()
return false
} }
} }
func downloadPlugin(completionHandler: @escaping (Result<URL, Error>) -> Void)
{
let pluginURL = URL(string: "https://f000.backblazeb2.com/file/altstore/altserver/altplugin/1_0.zip")!
let downloadTask = URLSession.shared.downloadTask(with: pluginURL) { (fileURL, response, error) in
if let fileURL = fileURL
{
print("Downloaded plugin to URL:", fileURL)
completionHandler(.success(fileURL))
}
else
{
completionHandler(.failure(error ?? PluginError.unknown))
}
}
downloadTask.resume()
}
func uninstallMailPlugin(completionHandler: @escaping (Result<Void, Error>) -> Void)
{
let alert = NSAlert()
alert.messageText = NSLocalizedString("Uninstall Mail Plug-in", comment: "")
alert.informativeText = NSLocalizedString("Are you sure you want to uninstall the AltServer Mail plug-in? You will no longer be able to install or refresh apps with AltStore.", comment: "")
alert.addButton(withTitle: NSLocalizedString("Uninstall Plug-in", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
let response = alert.runModal()
guard response == .alertFirstButtonReturn else { return completionHandler(.failure(PluginError.cancelled)) }
DispatchQueue.global().async {
do
{
if FileManager.default.fileExists(atPath: pluginURL.path)
{
// Delete Mail plug-in from privileged directory.
try self.run("rm", arguments: ["-rf", pluginURL.path])
}
completionHandler(.success(()))
}
catch
{
completionHandler(.failure(error))
}
}
}
}
private extension AppDelegate
{
func run(_ program: String, arguments: [String], authorization: AuthorizationRef? = nil) throws
{
_ = try self._run(program, arguments: arguments, authorization: authorization, freeAuthorization: true)
}
func runAndKeepAuthorization(_ program: String, arguments: [String], authorization: AuthorizationRef? = nil) throws -> AuthorizationRef
{
return try self._run(program, arguments: arguments, authorization: authorization, freeAuthorization: false)
}
func _run(_ program: String, arguments: [String], authorization: AuthorizationRef? = nil, freeAuthorization: Bool) throws -> AuthorizationRef
{
var launchPath = "/usr/bin/" + program
if !FileManager.default.fileExists(atPath: launchPath)
{
launchPath = "/bin/" + program
}
print("Running program:", launchPath)
let task = STPrivilegedTask()
task.launchPath = launchPath
task.arguments = arguments
task.freeAuthorizationWhenDone = freeAuthorization
let errorCode: OSStatus
if let authorization = authorization
{
errorCode = task.launch(withAuthorization: authorization)
}
else
{
errorCode = task.launch()
}
guard errorCode == 0 else { throw PluginError.taskErrorCode(Int(errorCode)) }
task.waitUntilExit()
guard task.terminationStatus == 0 else {
let outputData = task.outputFileHandle.readDataToEndOfFile()
if let outputString = String(data: outputData, encoding: .utf8), !outputString.isEmpty
{
throw PluginError.taskError(outputString)
}
throw PluginError.taskErrorCode(Int(task.terminationStatus))
}
guard let authorization = task.authorization else { throw PluginError.unknown }
return authorization
}
} }
extension AppDelegate: NSMenuDelegate extension AppDelegate: NSMenuDelegate

View File

@@ -1,13 +0,0 @@
#!/bin/sh
# InstallAltPlugin.sh
# AltStore
#
# Created by Riley Testut on 11/16/19.
# Copyright © 2019 Riley Testut. All rights reserved.
rm -f AltPlugin.mailbundle
unzip AltPlugin.mailbundle.zip 1>/dev/null
mkdir -p /Library/Mail/Bundles
cp -r AltPlugin.mailbundle /Library/Mail/Bundles
defaults write "/Library/Preferences/com.apple.mail" EnableBundles 1

View File

@@ -1,9 +0,0 @@
#!/bin/sh
# UninstallPlugin.sh
# AltStore
#
# Created by Riley Testut on 11/16/19.
# Copyright © 2019 Riley Testut. All rights reserved.
rm -rf /Library/Mail/Bundles/AltPlugin.mailbundle

View File

@@ -115,7 +115,6 @@
BF45884B2298D55000BD7491 /* thread.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4588492298D55000BD7491 /* thread.h */; }; BF45884B2298D55000BD7491 /* thread.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4588492298D55000BD7491 /* thread.h */; };
BF4588882298DD3F00BD7491 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF4588872298DD3F00BD7491 /* libxml2.tbd */; }; BF4588882298DD3F00BD7491 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF4588872298DD3F00BD7491 /* libxml2.tbd */; };
BF4C7F2523801F0800B2556E /* AltSign.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9B63C5229DD44D002F0A62 /* AltSign.framework */; }; BF4C7F2523801F0800B2556E /* AltSign.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9B63C5229DD44D002F0A62 /* AltSign.framework */; };
BF4C7F27238086EB00B2556E /* InstallPlugin.sh in Resources */ = {isa = PBXBuildFile; fileRef = BF4C7F26238086EB00B2556E /* InstallPlugin.sh */; };
BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */; }; BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */; };
BF56D2AA23DF88310006506D /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2A923DF88310006506D /* AppID.swift */; }; BF56D2AA23DF88310006506D /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2A923DF88310006506D /* AppID.swift */; };
BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; }; BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; };
@@ -137,7 +136,6 @@
BF7C627423DBB78C00515A2D /* InstalledAppPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7C627323DBB78C00515A2D /* InstalledAppPolicy.swift */; }; BF7C627423DBB78C00515A2D /* InstalledAppPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7C627323DBB78C00515A2D /* InstalledAppPolicy.swift */; };
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; }; BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; };
BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; }; BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; };
BF914C262383703800E713BA /* AltPlugin.mailbundle.zip in Resources */ = {isa = PBXBuildFile; fileRef = BF914C252383703800E713BA /* AltPlugin.mailbundle.zip */; };
BF9A03C623C7DD0D000D08DB /* ClientConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9A03C523C7DD0D000D08DB /* ClientConnection.swift */; }; BF9A03C623C7DD0D000D08DB /* ClientConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9A03C523C7DD0D000D08DB /* ClientConnection.swift */; };
BF9ABA4522DCFF43008935CF /* BrowseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */; }; BF9ABA4522DCFF43008935CF /* BrowseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */; };
BF9ABA4722DD0638008935CF /* BrowseCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */; }; BF9ABA4722DD0638008935CF /* BrowseCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */; };
@@ -208,7 +206,6 @@
BFD5D6F4230DDB0A007955AB /* Campaign.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F3230DDB0A007955AB /* Campaign.swift */; }; BFD5D6F4230DDB0A007955AB /* Campaign.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F3230DDB0A007955AB /* Campaign.swift */; };
BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F5230DDB12007955AB /* Tier.swift */; }; BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F5230DDB12007955AB /* Tier.swift */; };
BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */; }; BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */; };
BFD80D572380C0F700B9C227 /* UninstallPlugin.sh in Resources */ = {isa = PBXBuildFile; fileRef = BFD80D562380C0F700B9C227 /* UninstallPlugin.sh */; };
BFDB5B1622EE90D300F74113 /* Date+RelativeDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */; }; BFDB5B1622EE90D300F74113 /* Date+RelativeDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */; };
BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */; }; BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */; };
BFDB6A0522A9AFB2007EA6D6 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */; }; BFDB6A0522A9AFB2007EA6D6 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */; };
@@ -422,7 +419,6 @@
BF4588872298DD3F00BD7491 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; }; BF4588872298DD3F00BD7491 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; };
BF4588962298DE6E00BD7491 /* libzip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = libzip.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BF4588962298DE6E00BD7491 /* libzip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = libzip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF4713A422976CFC00784A2F /* openssl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = openssl.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BF4713A422976CFC00784A2F /* openssl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = openssl.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF4C7F26238086EB00B2556E /* InstallPlugin.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = InstallPlugin.sh; sourceTree = "<group>"; };
BF54E81F2315EF0D000AE0D8 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = "<group>"; }; BF54E81F2315EF0D000AE0D8 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = "<group>"; };
BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = "<group>"; }; BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = "<group>"; };
BF56D2A823DF87570006506D /* AltStore 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 4.xcdatamodel"; sourceTree = "<group>"; }; BF56D2A823DF87570006506D /* AltStore 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 4.xcdatamodel"; sourceTree = "<group>"; };
@@ -456,7 +452,6 @@
BF7C627323DBB78C00515A2D /* InstalledAppPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledAppPolicy.swift; sourceTree = "<group>"; }; BF7C627323DBB78C00515A2D /* InstalledAppPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledAppPolicy.swift; sourceTree = "<group>"; };
BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = "<group>"; }; BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = "<group>"; };
BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; }; BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; };
BF914C252383703800E713BA /* AltPlugin.mailbundle.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = AltPlugin.mailbundle.zip; sourceTree = "<group>"; };
BF9A03C523C7DD0D000D08DB /* ClientConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConnection.swift; sourceTree = "<group>"; }; BF9A03C523C7DD0D000D08DB /* ClientConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConnection.swift; sourceTree = "<group>"; };
BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewController.swift; sourceTree = "<group>"; }; BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewController.swift; sourceTree = "<group>"; };
BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseCollectionViewCell.swift; sourceTree = "<group>"; }; BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseCollectionViewCell.swift; sourceTree = "<group>"; };
@@ -535,7 +530,6 @@
BFD5D6F3230DDB0A007955AB /* Campaign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Campaign.swift; sourceTree = "<group>"; }; BFD5D6F3230DDB0A007955AB /* Campaign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Campaign.swift; sourceTree = "<group>"; };
BFD5D6F5230DDB12007955AB /* Tier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tier.swift; sourceTree = "<group>"; }; BFD5D6F5230DDB12007955AB /* Tier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tier.swift; sourceTree = "<group>"; };
BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsComponents.swift; sourceTree = "<group>"; }; BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsComponents.swift; sourceTree = "<group>"; };
BFD80D562380C0F700B9C227 /* UninstallPlugin.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = UninstallPlugin.sh; sourceTree = "<group>"; };
BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+RelativeDate.swift"; sourceTree = "<group>"; }; BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+RelativeDate.swift"; sourceTree = "<group>"; };
BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BrowseCollectionViewCell.xib; sourceTree = "<group>"; }; BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BrowseCollectionViewCell.xib; sourceTree = "<group>"; };
BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = "<group>"; }; BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = "<group>"; };
@@ -885,9 +879,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BF458693229872EA00BD7491 /* Assets.xcassets */, BF458693229872EA00BD7491 /* Assets.xcassets */,
BF914C252383703800E713BA /* AltPlugin.mailbundle.zip */,
BF4C7F26238086EB00B2556E /* InstallPlugin.sh */,
BFD80D562380C0F700B9C227 /* UninstallPlugin.sh */,
); );
name = Resources; name = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1415,11 +1406,8 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
BF914C262383703800E713BA /* AltPlugin.mailbundle.zip in Resources */,
BFD80D572380C0F700B9C227 /* UninstallPlugin.sh in Resources */,
BF458694229872EA00BD7491 /* Assets.xcassets in Resources */, BF458694229872EA00BD7491 /* Assets.xcassets in Resources */,
BF458697229872EA00BD7491 /* Main.storyboard in Resources */, BF458697229872EA00BD7491 /* Main.storyboard in Resources */,
BF4C7F27238086EB00B2556E /* InstallPlugin.sh in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@@ -19,7 +19,7 @@ target 'AltServer' do
use_frameworks! use_frameworks!
# Pods for AltServer # Pods for AltServer
pod 'STPrivilegedTask' pod 'STPrivilegedTask', :git => 'https://github.com/rileytestut/STPrivilegedTask.git'
pod 'Sparkle' pod 'Sparkle'
end end

View File

@@ -14,7 +14,7 @@ PODS:
- Nuke (7.6.3) - Nuke (7.6.3)
- Roxas (0.1) - Roxas (0.1)
- Sparkle (1.21.3) - Sparkle (1.21.3)
- STPrivilegedTask (1.0.1) - STPrivilegedTask (1.0.7)
DEPENDENCIES: DEPENDENCIES:
- AltSign (from `Dependencies/AltSign`) - AltSign (from `Dependencies/AltSign`)
@@ -22,20 +22,26 @@ DEPENDENCIES:
- Nuke (~> 7.0) - Nuke (~> 7.0)
- Roxas (from `Dependencies/Roxas`) - Roxas (from `Dependencies/Roxas`)
- Sparkle - Sparkle
- STPrivilegedTask - STPrivilegedTask (from `https://github.com/rileytestut/STPrivilegedTask.git`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- KeychainAccess - KeychainAccess
- Nuke - Nuke
- Sparkle - Sparkle
- STPrivilegedTask
EXTERNAL SOURCES: EXTERNAL SOURCES:
AltSign: AltSign:
:path: Dependencies/AltSign :path: Dependencies/AltSign
Roxas: Roxas:
:path: Dependencies/Roxas :path: Dependencies/Roxas
STPrivilegedTask:
:git: https://github.com/rileytestut/STPrivilegedTask.git
CHECKOUT OPTIONS:
STPrivilegedTask:
:commit: c8dd3e41b23666d4010c86b052a921a8e5a320d0
:git: https://github.com/rileytestut/STPrivilegedTask.git
SPEC CHECKSUMS: SPEC CHECKSUMS:
AltSign: c3693fa5a4b6d0ec6bedb74a5d768fe58bd67b87 AltSign: c3693fa5a4b6d0ec6bedb74a5d768fe58bd67b87
@@ -43,8 +49,8 @@ SPEC CHECKSUMS:
Nuke: 44130e95e09463f8773ae4b96b90de1eba6b3350 Nuke: 44130e95e09463f8773ae4b96b90de1eba6b3350
Roxas: 1990039f843f5dc284918dc82375feb80020ef62 Roxas: 1990039f843f5dc284918dc82375feb80020ef62
Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708 Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708
STPrivilegedTask: 103f97827454e786074640cf89d303be344498c7 STPrivilegedTask: 56c3397238a1ec07720fb877a044898373cd2c68
PODFILE CHECKSUM: 467b50b42949f001543841f547fa6b427e29dc53 PODFILE CHECKSUM: 1503b17048964bd0586d5470e6ee1e57917934de
COCOAPODS: 1.8.4 COCOAPODS: 1.8.4

View File

@@ -0,0 +1,25 @@
{
"name": "STPrivilegedTask",
"version": "1.0.7",
"summary": "An NSTask-like wrapper around Mac OS X Security Framework's AuthorizationExecuteWithPrivileges()",
"description": "An NSTask-like wrapper around AuthorizationExecuteWithPrivileges() in the Security API to run shell commands with root privileges in Mac OS X.",
"homepage": "http://github.com/sveinbjornt/STPrivilegedTask",
"license": {
"type": "BSD"
},
"authors": {
"Sveinbjorn Thordarson": "sveinbjorn@sveinbjorn.org"
},
"platforms": {
"osx": "10.8"
},
"source": {
"git": "https://github.com/sveinbjornt/STPrivilegedTask.git",
"tag": "1.0.7"
},
"source_files": "STPrivilegedTask.{h,m}",
"exclude_files": "PrivilegedTaskExample",
"public_header_files": "STPrivilegedTask.h",
"frameworks": "Security",
"requires_arc": false
}

16
Pods/Manifest.lock generated
View File

@@ -14,7 +14,7 @@ PODS:
- Nuke (7.6.3) - Nuke (7.6.3)
- Roxas (0.1) - Roxas (0.1)
- Sparkle (1.21.3) - Sparkle (1.21.3)
- STPrivilegedTask (1.0.1) - STPrivilegedTask (1.0.7)
DEPENDENCIES: DEPENDENCIES:
- AltSign (from `Dependencies/AltSign`) - AltSign (from `Dependencies/AltSign`)
@@ -22,20 +22,26 @@ DEPENDENCIES:
- Nuke (~> 7.0) - Nuke (~> 7.0)
- Roxas (from `Dependencies/Roxas`) - Roxas (from `Dependencies/Roxas`)
- Sparkle - Sparkle
- STPrivilegedTask - STPrivilegedTask (from `https://github.com/rileytestut/STPrivilegedTask.git`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- KeychainAccess - KeychainAccess
- Nuke - Nuke
- Sparkle - Sparkle
- STPrivilegedTask
EXTERNAL SOURCES: EXTERNAL SOURCES:
AltSign: AltSign:
:path: Dependencies/AltSign :path: Dependencies/AltSign
Roxas: Roxas:
:path: Dependencies/Roxas :path: Dependencies/Roxas
STPrivilegedTask:
:git: https://github.com/rileytestut/STPrivilegedTask.git
CHECKOUT OPTIONS:
STPrivilegedTask:
:commit: c8dd3e41b23666d4010c86b052a921a8e5a320d0
:git: https://github.com/rileytestut/STPrivilegedTask.git
SPEC CHECKSUMS: SPEC CHECKSUMS:
AltSign: c3693fa5a4b6d0ec6bedb74a5d768fe58bd67b87 AltSign: c3693fa5a4b6d0ec6bedb74a5d768fe58bd67b87
@@ -43,8 +49,8 @@ SPEC CHECKSUMS:
Nuke: 44130e95e09463f8773ae4b96b90de1eba6b3350 Nuke: 44130e95e09463f8773ae4b96b90de1eba6b3350
Roxas: 1990039f843f5dc284918dc82375feb80020ef62 Roxas: 1990039f843f5dc284918dc82375feb80020ef62
Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708 Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708
STPrivilegedTask: 103f97827454e786074640cf89d303be344498c7 STPrivilegedTask: 56c3397238a1ec07720fb877a044898373cd2c68
PODFILE CHECKSUM: 467b50b42949f001543841f547fa6b427e29dc53 PODFILE CHECKSUM: 1503b17048964bd0586d5470e6ee1e57917934de
COCOAPODS: 1.8.4 COCOAPODS: 1.8.4

View File

@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 50; objectVersion = 51;
objects = { objects = {
/* Begin PBXAggregateTarget section */ /* Begin PBXAggregateTarget section */
@@ -2211,7 +2211,7 @@
LastUpgradeCheck = 1100; LastUpgradeCheck = 1100;
}; };
buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 9.3"; compatibilityVersion = "Xcode 10.0";
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
@@ -2532,45 +2532,6 @@
}; };
name = Debug; name = Debug;
}; };
01FC26EF7492A83715733D6E82B58E10 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B763A613B013538736809BCA42B6DEF0 /* STPrivilegedTask.xcconfig */;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_WEAK = NO;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_PREFIX_HEADER = "Target Support Files/STPrivilegedTask/STPrivilegedTask-prefix.pch";
INFOPLIST_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
MODULEMAP_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask.modulemap";
PRODUCT_MODULE_NAME = STPrivilegedTask;
PRODUCT_NAME = STPrivilegedTask;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
03A826C198089C15D11AC65F5BED730D /* Debug */ = { 03A826C198089C15D11AC65F5BED730D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 3A44D4EBF7CD579B73B275F0F125F846 /* Pods-AltServer.debug.xcconfig */; baseConfigurationReference = 3A44D4EBF7CD579B73B275F0F125F846 /* Pods-AltServer.debug.xcconfig */;
@@ -2843,45 +2804,6 @@
}; };
name = Release; name = Release;
}; };
569B2F7FFE1A40245840B5BD14E5075B /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B763A613B013538736809BCA42B6DEF0 /* STPrivilegedTask.xcconfig */;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_WEAK = NO;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_PREFIX_HEADER = "Target Support Files/STPrivilegedTask/STPrivilegedTask-prefix.pch";
INFOPLIST_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
MODULEMAP_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask.modulemap";
PRODUCT_MODULE_NAME = STPrivilegedTask;
PRODUCT_NAME = STPrivilegedTask;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
5AFD67EFA6B3F27B4F0B0F8027C335F7 /* Debug */ = { 5AFD67EFA6B3F27B4F0B0F8027C335F7 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 5B1BF3395506426B10A06E5307D1EEFA /* Sparkle.xcconfig */; baseConfigurationReference = 5B1BF3395506426B10A06E5307D1EEFA /* Sparkle.xcconfig */;
@@ -3044,6 +2966,44 @@
}; };
name = Debug; name = Debug;
}; };
DAA2BB16DE5BB8A33D1F4FEBC5F6E540 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B763A613B013538736809BCA42B6DEF0 /* STPrivilegedTask.xcconfig */;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_PREFIX_HEADER = "Target Support Files/STPrivilegedTask/STPrivilegedTask-prefix.pch";
INFOPLIST_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
MODULEMAP_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask.modulemap";
PRODUCT_MODULE_NAME = STPrivilegedTask;
PRODUCT_NAME = STPrivilegedTask;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
E8921B3E2DFC77CDA00FEE1D9EA36AA0 /* Release */ = { E8921B3E2DFC77CDA00FEE1D9EA36AA0 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 1215053FA027E4CE849DAF4D00697FF1 /* Pods-AltServer.release.xcconfig */; baseConfigurationReference = 1215053FA027E4CE849DAF4D00697FF1 /* Pods-AltServer.release.xcconfig */;
@@ -3085,6 +3045,44 @@
}; };
name = Release; name = Release;
}; };
F53E3123D6E0B1A60F1DFB065889DFD7 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B763A613B013538736809BCA42B6DEF0 /* STPrivilegedTask.xcconfig */;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_PREFIX_HEADER = "Target Support Files/STPrivilegedTask/STPrivilegedTask-prefix.pch";
INFOPLIST_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
MODULEMAP_FILE = "Target Support Files/STPrivilegedTask/STPrivilegedTask.modulemap";
PRODUCT_MODULE_NAME = STPrivilegedTask;
PRODUCT_NAME = STPrivilegedTask;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@@ -3118,8 +3116,8 @@
54208ED19403AA500F1198EEF237E880 /* Build configuration list for PBXNativeTarget "STPrivilegedTask" */ = { 54208ED19403AA500F1198EEF237E880 /* Build configuration list for PBXNativeTarget "STPrivilegedTask" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
01FC26EF7492A83715733D6E82B58E10 /* Debug */, F53E3123D6E0B1A60F1DFB065889DFD7 /* Debug */,
569B2F7FFE1A40245840B5BD14E5075B /* Release */, DAA2BB16DE5BB8A33D1F4FEBC5F6E540 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;

29
Pods/STPrivilegedTask/LICENSE generated Normal file
View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2009, Sveinbjorn Thordarson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,22 +0,0 @@
# BSD License
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other
# contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,58 +1,193 @@
# STPrivilegedTask - Objective C class # STPrivilegedTask - Objective C class
An NSTask-like wrapper around AuthorizationExecuteWithPrivileges() in the Security API to run shell commands with root privileges in Mac OS X. An NSTask-like wrapper around [AuthorizationExecuteWithPrivileges()](https://developer.apple.com/library/mac/documentation/Security/Reference/authorization_ref/#//apple_ref/c/func/AuthorizationExecuteWithPrivileges) in the Security API to run shell commands with root privileges in Mac OS X.
Example of usage: STPrivilegedTask was created a long time ago. It has now been updated to support ARC and is available via <a href="https://cocoapods.org">CocoaPods</a>.
## Examples
### Create and launch task
```objective-c ```objective-c
// Create task
STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init]; STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init];
[privilegedTask setLaunchPath:@"/usr/bin/touch"]; [privilegedTask setLaunchPath:@"/usr/bin/touch"];
NSArray *args = [NSArray arrayWithObject:@"/etc/my_test_file"]; [privilegedTask setArguments:@[@"/etc/my_test_file"]];
[privilegedTask setArguments:args];
[privilegedTask setCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];
//set it off // Setting working directory is optional, defaults to /
// NSString *path = [[NSBundle mainBundle] resourcePath];
// [privilegedTask setCurrentDirectoryPath:path];
// Launch it, user is prompted for password
OSStatus err = [privilegedTask launch]; OSStatus err = [privilegedTask launch];
if (err != errAuthorizationSuccess) { if (err == errAuthorizationSuccess) {
if (err == errAuthorizationCanceled) { NSLog(@"Task successfully launched");
NSLog(@"User cancelled");
} else {
NSLog(@"Something went wrong");
}
} }
else if (err == errAuthorizationCanceled) {
NSLog(@"User cancelled");
}
else {
NSLog(@"Something went wrong");
}
```
See [Authorization.h](http://www.opensource.apple.com/source/libsecurity_authorization/libsecurity_authorization-36329/lib/Authorization.h) for a list of possible error codes.
### Launch task one-liner
```objective-c
OSStatus err = [STPrivilegedTask launchedPrivilegedTaskWithLaunchPath:@"/bin/sh"
arguments:@[@"/path/to/script.sh"]];
```
### Getting task output
```objective-c
// ... launch task
[privilegedTask waitUntilExit];
// Read output file handle for data // Read output file handle for data
NSFileHandle *readHandle = [privilegedTask outputFileHandle]; NSData *outputData = [[privilegedTask outputFileHandle] readDataToEndOfFile];
NSData *outputData = [readHandle readDataToEndOfFile];
NSString *outputString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; NSString *outputString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
``` ```
# BSD License ### Getting output while task runs in background
```objective-c
// ... launch task
NSFileHandle *readHandle = [privilegedTask outputFileHandle];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getOutputData:) name:NSFileHandleReadCompletionNotification object:readHandle];
[readHandle readInBackgroundAndNotify];
// ...
- (void)getOutputData:(NSNotification *)aNotification {
//get data from notification
NSData *data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem];
//make sure there's actual data
if ([data length]) {
// do something with the data
NSString *outputString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(outputString);
// go read more data in the background
[[aNotification object] readInBackgroundAndNotify];
} else {
// do something else
}
}
``` ```
# Redistribution and use in source and binary forms, with or without ### Task termination
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other
# contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
``` You can observe STPrivilegedTaskDidTerminateNotification:
```objective-c
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(privilegedTaskFinished:) name:STPrivilegedTaskDidTerminateNotification object:nil];
- (void)privilegedTaskFinished:(NSNotification *)aNotification {
// do something
}
```
Or alternately, set a termination handler:
```objective-c
privilegedTask.terminationHandler = ^(STPrivilegedTask *privilegedTask) {
NSLog(@"Terminating task: %@", [privilegedTask description]);
};
```
### Launch using external AuthorizationRef
```objective-c
// ... Create your own AuthorizationRef
[STPriviledTask launchedPrivilegedTaskWithLaunchPath:@"/bin/sh"
arguments:@"/path/to/script"
currentDirectory:@"/"
authorization:authRef]
```
### AuthorizationExecuteWithPrivileges() is deprecated
[AuthorizationExecuteWithPrivileges()](https://developer.apple.com/library/mac/documentation/Security/Reference/authorization_ref/#//apple_ref/c/func/AuthorizationExecuteWithPrivileges) is deprecated as of macOS 10.7 but remains available
in 10.14 Mojave. If you want to be future-proof, here's how you check if STPrivilegedTask
works in the running version of macOS:
```objective-c
OSStatus err = [privilegedTask launch];
if (err == errAuthorizationFnNoLongerExists) {
NSLog(@"AuthorizationExecuteWithPrivileges not available");
}
```
If you need to check whether STPrivilegedTask works before you launch the task:
```objective-c
BOOL works = [STPrivilegedTask authorizationFunctionAvailable];
```
## Sample app
A sample app which makes use of STPrivilegedTask is included in the project. This app runs the following script:
```
#!/bin/sh
echo "/usr/bin/whoami:"
whoami
echo ""
echo "Real User ID:"
echo $UID \($USER\)
echo ""
echo "Effective User ID:"
/usr/bin/id -u
echo ""
echo "Current working directory:"
echo "$PWD"
exit 5
```
It then presents the output of the script in a window, along with the exit code.
<img src="screenshot.png">
## BSD License
Copyright (c) Sveinbjorn Thordarson &lt;sveinbjorn@sveinbjorn.org&gt;
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

84
Pods/STPrivilegedTask/STPrivilegedTask.h generated Normal file → Executable file
View File

@@ -1,7 +1,6 @@
/* /*
#
# STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges # STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges
# Copyright (C) 2009-2015 Sveinbjorn Thordarson <sveinbjornt@gmail.com> # Copyright (C) 2009-2017 Sveinbjorn Thordarson <sveinbjorn@sveinbjorn.org>
# #
# BSD License # BSD License
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@@ -11,7 +10,7 @@
# * Redistributions in binary form must reproduce the above copyright # * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the # notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution. # documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other # * Neither the name of the copyright holder nor that of any other
# contributors may be used to endorse or promote products # contributors may be used to endorse or promote products
# derived from this software without specific prior written permission. # derived from this software without specific prior written permission.
# #
@@ -28,54 +27,43 @@
*/ */
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
#define STPrivilegedTaskDidTerminateNotification @"STPrivilegedTaskDidTerminateNotification" #define STPrivilegedTaskDidTerminateNotification @"STPrivilegedTaskDidTerminateNotification"
//#define TMP_STDERR_TEMPLATE @".authStderr.XXXXXX"
// Defines error value for when AuthorizationExecuteWithPrivilleges no longer // Defines error value for when AuthorizationExecuteWithPrivileges no longer exists
// exists anyplace. Rather than defining a new enum, we just create a global // Rather than defining a new enum, we just create a global constant
// constant
extern const OSStatus errAuthorizationFnNoLongerExists; extern const OSStatus errAuthorizationFnNoLongerExists;
@interface STPrivilegedTask : NSObject @interface STPrivilegedTask : NSObject
{
NSArray *arguments; @property (copy) NSArray *arguments;
NSString *cwd; @property (copy) NSString *currentDirectoryPath;
NSString *launchPath; @property (copy) NSString *launchPath;
BOOL isRunning; @property (assign) BOOL freeAuthorizationWhenDone;
pid_t pid;
int terminationStatus; @property (readonly) NSFileHandle *outputFileHandle;
NSFileHandle *outputFileHandle; @property (readonly) BOOL isRunning;
NSTimer *checkStatusTimer; @property (readonly) pid_t processIdentifier;
} @property (readonly) int terminationStatus;
-(id)initWithLaunchPath:(NSString *)path; @property (readonly) AuthorizationRef authorization;
-(id)initWithLaunchPath:(NSString *)path arguments: (NSArray *)args;
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path; @property (copy) void (^terminationHandler)(STPrivilegedTask *);
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;
-(NSArray *)arguments; + (BOOL)authorizationFunctionAvailable;
-(NSString *)currentDirectoryPath;
-(BOOL)isRunning; - (instancetype)initWithLaunchPath:(NSString *)path;
-(int)launch; - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args;
-(NSString *)launchPath; - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd;
-(int)processIdentifier;
-(void)setArguments:(NSArray *)arguments; + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path;
-(void)setCurrentDirectoryPath:(NSString *)path; + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args;
-(void)setLaunchPath:(NSString *)path; + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd;
-(NSFileHandle *)outputFileHandle; + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd authorization:(AuthorizationRef)authorization;
-(void)terminate; // doesn't work
-(int)terminationStatus; - (OSStatus)launch;
-(void)_checkTaskStatus; - (OSStatus)launchWithAuthorization:(AuthorizationRef)authorization;
-(void)waitUntilExit; - (void)terminate; // doesn't work
- (void)waitUntilExit;
@end @end
/*static OSStatus AuthorizationExecuteWithPrivilegesStdErrAndPid (
AuthorizationRef authorization,
const char *pathToTool,
AuthorizationFlags options,
char * const *arguments,
FILE **communicationsPipe,
FILE **errPipe,
pid_t* processid
);*/

496
Pods/STPrivilegedTask/STPrivilegedTask.m generated Normal file → Executable file
View File

@@ -1,7 +1,6 @@
/* /*
#
# STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges # STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges
# Copyright (C) 2009-2015 Sveinbjorn Thordarson <sveinbjornt@gmail.com> # Copyright (C) 2009-2017 Sveinbjorn Thordarson <sveinbjorn@sveinbjorn.org>
# #
# BSD License # BSD License
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@@ -11,7 +10,7 @@
# * Redistributions in binary form must reproduce the above copyright # * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the # notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution. # documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other # * Neither the name of the copyright holder nor that of any other
# contributors may be used to endorse or promote products # contributors may be used to endorse or promote products
# derived from this software without specific prior written permission. # derived from this software without specific prior written permission.
# #
@@ -25,192 +24,154 @@
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#import "STPrivilegedTask.h" #import "STPrivilegedTask.h"
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
#import <stdio.h> #import <stdio.h>
#import <unistd.h> #import <unistd.h>
#import <dlfcn.h> #import <dlfcn.h>
/* New error code denoting that AuthorizationExecuteWithPrivileges no longer exists */ // New error code denoting that AuthorizationExecuteWithPrivileges no longer exists
OSStatus const errAuthorizationFnNoLongerExists = -70001; OSStatus const errAuthorizationFnNoLongerExists = -70001;
// Create fn pointer to AuthorizationExecuteWithPrivileges in case
// it doesn't exist in this version of MacOS
static OSStatus (*_AuthExecuteWithPrivsFn)(AuthorizationRef authorization, const char *pathToTool, AuthorizationFlags options,
char * const *arguments, FILE **communicationsPipe) = NULL;
@implementation STPrivilegedTask @implementation STPrivilegedTask
- (id)init
{ {
if ((self = [super init])) { NSTimer *_checkStatusTimer;
launchPath = @""; }
cwd = [[NSString alloc] initWithString:[[NSFileManager defaultManager] currentDirectoryPath]];
arguments = [[NSArray alloc] init]; + (void)initialize;
isRunning = NO; {
outputFileHandle = nil; // On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want
// to still use it since there's no good alternative (without requiring
// code signing). We'll look up the function through dyld and fail if
// it is no longer accessible. If Apple removes the function entirely
// this will fail gracefully. If they keep the function and throw some
// sort of exception, this won't fail gracefully, but that's a risk
// we'll have to take for now.
// Pattern by Andy Kim from Potion Factory LLC
#pragma GCC diagnostic ignored "-Wpedantic" // stop the pedantry!
#pragma clang diagnostic push
_AuthExecuteWithPrivsFn = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
#pragma clang diagnostic pop
}
- (instancetype)init
{
self = [super init];
if (self) {
_launchPath = nil;
_arguments = nil;
_freeAuthorizationWhenDone = YES;
_isRunning = NO;
_outputFileHandle = nil;
_terminationHandler = nil;
_authorization = nil;
_currentDirectoryPath = [[NSFileManager defaultManager] currentDirectoryPath];
} }
return self; return self;
} }
-(void)dealloc - (instancetype)initWithLaunchPath:(NSString *)path
{ {
#if !__has_feature(objc_arc) self = [self init];
[launchPath release]; if (self) {
[arguments release]; self.launchPath = path;
[cwd release];
if (outputFileHandle != nil) {
[outputFileHandle release];
}
[super dealloc];
#endif
}
-(id)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args
{
if ((self = [self initWithLaunchPath:path])) {
[self setArguments:args];
} }
return self; return self;
} }
-(id)initWithLaunchPath:(NSString *)path - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args
{ {
if ((self = [self init])) { self = [self initWithLaunchPath:path];
[self setLaunchPath:path]; if (self) {
self.arguments = args;
} }
return self; return self;
} }
- (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd
{
self = [self initWithLaunchPath:path arguments:args];
if (self) {
self.currentDirectoryPath = cwd;
}
return self;
}
- (void)dealloc
{
if (_freeAuthorizationWhenDone && _authorization != nil) {
// free the auth ref
AuthorizationFree(_authorization, kAuthorizationFlagDefaults);
}
}
#pragma mark - #pragma mark -
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path
{
STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args];
#if !__has_feature(objc_arc)
[task autorelease];
#endif
[task launch];
[task waitUntilExit];
return task;
}
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path
{ {
STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path]; STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path];
#if !__has_feature(objc_arc)
[task autorelease];
#endif
[task launch]; [task launch];
[task waitUntilExit]; [task waitUntilExit];
return task; return task;
} }
#pragma mark - + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args
- (NSArray *)arguments
{ {
return arguments; STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args];
[task launch];
[task waitUntilExit];
return task;
} }
- (NSString *)currentDirectoryPath; + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd
{ {
return cwd; STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args currentDirectory:cwd];
[task launch];
[task waitUntilExit];
return task;
} }
- (BOOL)isRunning + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd authorization:(AuthorizationRef)authorization
{ {
return isRunning; STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args currentDirectory:cwd];
} [task launchWithAuthorization:authorization];
[task waitUntilExit];
- (NSString *)launchPath return task;
{
return launchPath;
}
- (int)processIdentifier
{
return pid;
}
- (int)terminationStatus
{
return terminationStatus;
}
- (NSFileHandle *)outputFileHandle;
{
return outputFileHandle;
}
#pragma mark -
-(void)setArguments:(NSArray *)args
{
#if !__has_feature(objc_arc)
[arguments release];
[args retain];
#endif
arguments = args;
}
-(void)setCurrentDirectoryPath:(NSString *)path
{
#if !__has_feature(objc_arc)
[cwd release];
[path retain];
#endif
cwd = path;
}
-(void)setLaunchPath:(NSString *)path
{
#if !__has_feature(objc_arc)
[launchPath release];
[path retain];
#endif
launchPath = path;
} }
# pragma mark - # pragma mark -
// return 0 for success // return 0 for success
-(int)launch - (OSStatus)launch
{ {
if (_isRunning) {
NSLog(@"Task already running: %@", [self description]);
return 0;
}
if ([STPrivilegedTask authorizationFunctionAvailable] == NO) {
NSLog(@"AuthorizationExecuteWithPrivileges() function not available on this system");
return errAuthorizationFnNoLongerExists;
}
OSStatus err = noErr; OSStatus err = noErr;
const char *toolPath = [launchPath fileSystemRepresentation]; const char *toolPath = [self.launchPath fileSystemRepresentation];
AuthorizationRef authorizationRef; AuthorizationRef authorizationRef;
AuthorizationItem myItems = {kAuthorizationRightExecute, strlen(toolPath), &toolPath, 0}; AuthorizationItem myItems = { kAuthorizationRightExecute, strlen(toolPath), &toolPath, 0 };
AuthorizationRights myRights = {1, &myItems}; AuthorizationRights myRights = { 1, &myItems };
AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
NSUInteger numberOfArguments = [arguments count];
char *args[numberOfArguments + 1];
FILE *outputFile;
// Create fn pointer to AuthorizationExecuteWithPrivileges in case it doesn't exist
// in this version of MacOS
static OSStatus (*_AuthExecuteWithPrivsFn)(
AuthorizationRef authorization, const char *pathToTool, AuthorizationFlags options,
char * const *arguments, FILE **communicationsPipe) = NULL;
// Check to see if we have the correct function in our loaded libraries
if (!_AuthExecuteWithPrivsFn) {
// On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want
// to still use it since there's no good alternative (without requiring
// code signing). We'll look up the function through dyld and fail if
// it is no longer accessible. If Apple removes the function entirely
// this will fail gracefully. If they keep the function and throw some
// sort of exception, this won't fail gracefully, but that's a risk
// we'll have to take for now.
// Pattern by Andy Kim from Potion Factory LLC
_AuthExecuteWithPrivsFn = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
if (!_AuthExecuteWithPrivsFn) {
// This version of OS X has finally removed this function. Exit with an error.
err = errAuthorizationFnNoLongerExists;
return err;
}
}
// Use Apple's Authentication Manager APIs to get an Authorization Reference // Use Apple's Authentication Manager APIs to get an Authorization Reference
// These Apple APIs are quite possibly the most horrible of the Mac OS X APIs // These Apple APIs are quite possibly the most horrible of the Mac OS X APIs
@@ -227,24 +188,51 @@ OSStatus const errAuthorizationFnNoLongerExists = -70001;
} }
// OK, at this point we have received authorization for the task. // OK, at this point we have received authorization for the task.
err = [self launchWithAuthorization:authorizationRef];
return err;
}
- (OSStatus)launchWithAuthorization:(AuthorizationRef)authorization
{
_authorization = authorization;
if (_isRunning) {
NSLog(@"Task already running: %@", [self description]);
return 0;
}
if ([STPrivilegedTask authorizationFunctionAvailable] == NO) {
NSLog(@"AuthorizationExecuteWithPrivileges() function not available on this system");
return errAuthorizationFnNoLongerExists;
}
// Assuming the authorization is valid for the task.
// Let's prepare to launch it // Let's prepare to launch it
NSArray *arguments = self.arguments;
NSUInteger numberOfArguments = [arguments count];
char *args[numberOfArguments + 1];
FILE *outputFile;
const char *toolPath = [self.launchPath fileSystemRepresentation];
// first, construct an array of c strings from NSArray w. arguments // first, construct an array of c strings from NSArray w. arguments
for (int i = 0; i < numberOfArguments; i++) { for (int i = 0; i < numberOfArguments; i++) {
NSString *argString = arguments[i]; NSString *argString = arguments[i];
NSUInteger stringLength = [argString length]; const char *fsrep = [argString fileSystemRepresentation];
NSUInteger stringLength = strlen(fsrep);
args[i] = malloc((stringLength + 1) * sizeof(char)); args[i] = malloc((stringLength + 1) * sizeof(char));
snprintf(args[i], stringLength + 1, "%s", [argString fileSystemRepresentation]); snprintf(args[i], stringLength + 1, "%s", fsrep);
} }
args[numberOfArguments] = NULL; args[numberOfArguments] = NULL;
// change to the current dir specified // change to the current dir specified
char *prevCwd = (char *)getcwd(nil, 0); char *prevCwd = (char *)getcwd(nil, 0);
chdir([cwd fileSystemRepresentation]); chdir([self.currentDirectoryPath fileSystemRepresentation]);
//use Authorization Reference to execute script with privileges //use Authorization Reference to execute script with privileges
err = _AuthExecuteWithPrivsFn(authorizationRef, [launchPath fileSystemRepresentation], kAuthorizationFlagDefaults, args, &outputFile); OSStatus err = _AuthExecuteWithPrivsFn(authorization, toolPath, kAuthorizationFlagDefaults, args, &outputFile);
// OK, now we're done executing, let's change back to old dir // OK, now we're done executing, let's change back to old dir
chdir(prevCwd); chdir(prevCwd);
@@ -254,208 +242,92 @@ OSStatus const errAuthorizationFnNoLongerExists = -70001;
free(args[i]); free(args[i]);
} }
// free the auth ref
AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
// we return err if execution failed // we return err if execution failed
if (err != errAuthorizationSuccess) { if (err != errAuthorizationSuccess) {
return err; return err;
} else { } else {
isRunning = YES; _isRunning = YES;
} }
// get file handle for the command output // get file handle for the command output
outputFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(outputFile) closeOnDealloc:YES]; _outputFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(outputFile) closeOnDealloc:YES];
pid = fcntl(fileno(outputFile), F_GETOWN, 0); _processIdentifier = fcntl(fileno(outputFile), F_GETOWN, 0);
// start monitoring task // start monitoring task
checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:0.10 target:self selector:@selector(_checkTaskStatus) userInfo:nil repeats:YES]; _checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(checkTaskStatus) userInfo:nil repeats:YES];
return err; return err;
} }
- (void)terminate - (void)terminate
{ {
// This doesn't work without a PID, and we can't get one. Stupid Security API // This doesn't work without a PID, and we can't get one. Stupid Security API.
/* int ret = kill(pid, SIGKILL); // int ret = kill(pid, SIGKILL);
//
if (ret != 0) // if (ret != 0) {
NSLog(@"Error %d", errno);*/ // NSLog(@"Error %d", errno);
// }
} }
// hang until task is done // hang until task is done
- (void)waitUntilExit - (void)waitUntilExit
{ {
waitpid([self processIdentifier], &terminationStatus, 0); if (!_isRunning) {
isRunning = NO; NSLog(@"Task %@ is not running", [super description]);
return;
}
[_checkStatusTimer invalidate];
int status;
pid_t pid = 0;
while ((pid = waitpid(_processIdentifier, &status, WNOHANG)) == 0) {
// do nothing
}
_terminationStatus = WEXITSTATUS(status);
_isRunning = NO;
} }
#pragma mark - // check if task has terminated
- (void)checkTaskStatus
// check if privileged task is still running {
- (void)_checkTaskStatus int status;
{ pid_t pid = waitpid(_processIdentifier, &status, WNOHANG);
// see if task has terminated if (pid != 0) {
int mypid = waitpid([self processIdentifier], &terminationStatus, WNOHANG); _isRunning = NO;
if (mypid != 0) { _terminationStatus = WEXITSTATUS(status);
isRunning = NO; [_checkStatusTimer invalidate];
[[NSNotificationCenter defaultCenter] postNotificationName:STPrivilegedTaskDidTerminateNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:STPrivilegedTaskDidTerminateNotification object:self];
[checkStatusTimer invalidate]; if (_terminationHandler) {
_terminationHandler(self);
}
} }
} }
#pragma mark - #pragma mark -
+ (BOOL)authorizationFunctionAvailable
{
if (!_AuthExecuteWithPrivsFn) {
// This version of OS X has finally removed this function. Return with an error.
return NO;
}
return YES;
}
#pragma mark -
// Nice description for debugging
- (NSString *)description - (NSString *)description
{ {
NSArray *args = [self arguments]; NSString *commandDescription = [NSString stringWithString:self.launchPath];
NSString *cmd = [[self launchPath] copy];
for (int i = 0; i < [args count]; i++) { for (NSString *arg in self.arguments) {
cmd = [cmd stringByAppendingFormat:@" %@", args[i]]; commandDescription = [commandDescription stringByAppendingFormat:@" '%@'", arg];
} }
[commandDescription stringByAppendingFormat:@" (CWD:%@)", self.currentDirectoryPath];
return [[super description] stringByAppendingFormat:@" %@", cmd]; return [[super description] stringByAppendingFormat:@" %@", commandDescription];
} }
@end @end
/*
*
* Add the Standard err Pipe and Pid support to AuthorizationExecuteWithPrivileges()
* method
*
* @Author: Miklós Fazekas
* Modified Aug 10 2010 by Sveinbjorn Thordarson
*
*/
/*static OSStatus AuthorizationExecuteWithPrivilegesStdErrAndPid (
AuthorizationRef authorization,
const char *pathToTool,
AuthorizationFlags options,
char * const *arguments,
FILE **communicationsPipe,
FILE **errPipe,
pid_t* processid
)
{
// get the Apple-approved secure temp directory
NSString *tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent: TMP_STDERR_TEMPLATE];
// copy it into a C string
const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
char *stderrpath = (char *)malloc(strlen(tempFileTemplateCString) + 1);
strcpy(stderrpath, tempFileTemplateCString);
printf("%s\n", stderrpath);
// this is the command, it echoes pid and directs stderr output to pipe before running the tool w. args
const char *commandtemplate = "echo $$; \"$@\" 2>%s";
if (communicationsPipe == errPipe)
commandtemplate = "echo $$; \"$@\" 2>1";
else if (errPipe == 0)
commandtemplate = "echo $$; \"$@\"";
char command[1024];
char **args;
OSStatus result;
int argcount = 0;
int i;
int stderrfd = 0;
FILE *commPipe = 0;
// First, create temporary file for stderr
if (errPipe)
{
// create temp file
stderrfd = mkstemp(stderrpath);
// close and remove it
close(stderrfd);
unlink(stderrpath);
// create a pipe on the path of the temp file
if (mkfifo(stderrpath,S_IRWXU | S_IRWXG) != 0)
{
fprintf(stderr,"Error mkfifo:%d\n", errno);
return errAuthorizationInternal;
}
if (stderrfd < 0)
return errAuthorizationInternal;
}
// Create command to be executed
for (argcount = 0; arguments[argcount] != 0; ++argcount) {}
args = (char**)malloc (sizeof(char*)*(argcount + 5));
args[0] = "-c";
snprintf (command, sizeof (command), commandtemplate, stderrpath);
args[1] = command;
args[2] = "";
args[3] = (char*)pathToTool;
for (i = 0; i < argcount; ++i) {
args[i+4] = arguments[i];
}
args[argcount+4] = 0;
// for debugging: log the executed command
printf ("Exec:\n%s", "/bin/sh"); for (i = 0; args[i] != 0; ++i) { printf (" \"%s\"", args[i]); } printf ("\n");
// Execute command
result = AuthorizationExecuteWithPrivileges(authorization, "/bin/sh", options, args, &commPipe );
if (result != noErr)
{
unlink (stderrpath);
return result;
}
// Read the first line of stdout => it's the pid
{
int stdoutfd = fileno (commPipe);
char pidnum[1024];
pid_t pid = 0;
int i = 0;
char ch = 0;
while ((read(stdoutfd, &ch, sizeof(ch)) == 1) && (ch != '\n') && (i < sizeof(pidnum)))
{
pidnum[i++] = ch;
}
pidnum[i] = 0;
if (ch != '\n')
{
// we shouldn't get there
unlink (stderrpath);
return errAuthorizationInternal;
}
sscanf(pidnum, "%d", &pid);
if (processid)
{
*processid = pid;
}
NSLog(@"Have PID %d", pid);
}
//
if (errPipe) {
stderrfd = open(stderrpath, O_RDONLY, 0);
// *errPipe = fdopen(stderrfd, "r");
//Now it's safe to unlink the stderr file, as the opened handle will be still valid
unlink (stderrpath);
} else {
unlink(stderrpath);
}
if (communicationsPipe)
*communicationsPipe = commPipe;
else
fclose (commPipe);
NSLog(@"AuthExecNew function over");
return noErr;
}*/

View File

@@ -3,28 +3,35 @@ This application makes use of the following third party libraries:
## STPrivilegedTask ## STPrivilegedTask
# BSD License BSD 3-Clause License
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: Copyright (c) 2009, Sveinbjorn Thordarson
# * Redistributions of source code must retain the above copyright All rights reserved.
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright Redistribution and use in source and binary forms, with or without
# notice, this list of conditions and the following disclaimer in the modification, are permitted provided that the following conditions are met:
# documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other * Redistributions of source code must retain the above copyright notice, this
# contributors may be used to endorse or promote products list of conditions and the following disclaimer.
# derived from this software without specific prior written permission.
# * Redistributions in binary form must reproduce the above copyright notice,
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND this list of conditions and the following disclaimer in the documentation
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED and/or other materials provided with the distribution.
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * Neither the name of the copyright holder nor the names of its
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES contributors may be used to endorse or promote products derived from
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; this software without specific prior written permission.
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Sparkle ## Sparkle

View File

@@ -14,28 +14,35 @@
</dict> </dict>
<dict> <dict>
<key>FooterText</key> <key>FooterText</key>
<string> # BSD License <string>BSD 3-Clause License
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: Copyright (c) 2009, Sveinbjorn Thordarson
# * Redistributions of source code must retain the above copyright All rights reserved.
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright Redistribution and use in source and binary forms, with or without
# notice, this list of conditions and the following disclaimer in the modification, are permitted provided that the following conditions are met:
# documentation and/or other materials provided with the distribution.
# * Neither the name of Sveinbjorn Thordarson nor that of any other * Redistributions of source code must retain the above copyright notice, this
# contributors may be used to endorse or promote products list of conditions and the following disclaimer.
# derived from this software without specific prior written permission.
# * Redistributions in binary form must reproduce the above copyright notice,
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND this list of conditions and the following disclaimer in the documentation
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED and/or other materials provided with the distribution.
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * Neither the name of the copyright holder nor the names of its
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES contributors may be used to endorse or promote products derived from
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; this software without specific prior written permission.
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</string> </string>
<key>License</key> <key>License</key>
<string>BSD</string> <string>BSD</string>

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.1</string> <string>1.0.7</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>