[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.", @"");
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 STPrivilegedTask
private let pluginDirectoryURL = URL(fileURLWithPath: "/Library/Mail/Bundles", isDirectory: true)
private let pluginURL = pluginDirectoryURL.appendingPathComponent("AltPlugin.mailbundle")
enum PluginError: LocalizedError
{
case installationScriptNotFound
case failedToRun(Int)
case scriptError(String)
case cancelled
case unknown
case taskError(String)
case taskErrorCode(Int)
var errorDescription: String? {
switch self
{
case .installationScriptNotFound: return NSLocalizedString("The installation script could not be found.", comment: "")
case .failedToRun(let errorCode): return String(format: NSLocalizedString("The installation script could not be run. (%@)", comment: ""), NSNumber(value: errorCode))
case .scriptError(let output): return output
case .cancelled: return NSLocalizedString("Mail plug-in installation was cancelled.", comment: "")
case .unknown: return NSLocalizedString("Failed to install Mail plug-in.", comment: "")
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
class AppDelegate: NSObject, NSApplicationDelegate {
@@ -108,7 +111,7 @@ private extension AppDelegate
self.launchAtLoginMenuItem.state = LaunchAtLogin.isEnabled ? .on : .off
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: "")
}
@@ -182,47 +185,73 @@ private extension AppDelegate
let device = self.connectedDevices[index]
if !self.isMailPluginInstalled
func install()
{
let result = self.installMailPlugin()
guard result else { return }
ALTDeviceManager.shared.installAltStore(to: device, appleID: username, password: password) { (result) in
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
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
if !self.isMailPluginInstalled
{
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()
install()
}
}
else
{
alert.informativeText = error.localizedDescription
}
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
alert.runModal()
}
}
else
{
install()
}
}
@objc func toggleLaunchAtLogin(_ item: NSMenuItem)
@@ -241,71 +270,205 @@ private extension AppDelegate
@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() -> Bool
func installMailPlugin(completionHandler: @escaping (Result<Void, Error>) -> Void)
{
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
{
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: "")
alert.addButton(withTitle: NSLocalizedString("Install Plug-in", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
let response = alert.runModal()
guard response == .alertFirstButtonReturn else { return false }
alert.addButton(withTitle: NSLocalizedString("Install Plug-in", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
NSRunningApplication.current.activate(options: .activateIgnoringOtherApps)
let response = alert.runModal()
guard response == .alertFirstButtonReturn else { throw PluginError.cancelled }
self.downloadPlugin { (result) in
do
{
let fileURL = try result.get()
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
{
let alert = NSAlert()
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
completionHandler(.failure(PluginError.cancelled))
}
}
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

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 */; };
BF4588882298DD3F00BD7491 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF4588872298DD3F00BD7491 /* libxml2.tbd */; };
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 */; };
BF56D2AA23DF88310006506D /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2A923DF88310006506D /* AppID.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 */; };
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.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 */; };
BF9ABA4522DCFF43008935CF /* BrowseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4422DCFF43008935CF /* BrowseViewController.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 */; };
BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F5230DDB12007955AB /* Tier.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 */; };
BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */; };
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; };
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; };
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>"; };
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>"; };
@@ -456,7 +452,6 @@
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>"; };
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>"; };
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>"; };
@@ -535,7 +530,6 @@
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>"; };
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>"; };
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>"; };
@@ -885,9 +879,6 @@
isa = PBXGroup;
children = (
BF458693229872EA00BD7491 /* Assets.xcassets */,
BF914C252383703800E713BA /* AltPlugin.mailbundle.zip */,
BF4C7F26238086EB00B2556E /* InstallPlugin.sh */,
BFD80D562380C0F700B9C227 /* UninstallPlugin.sh */,
);
name = Resources;
sourceTree = "<group>";
@@ -1415,11 +1406,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BF914C262383703800E713BA /* AltPlugin.mailbundle.zip in Resources */,
BFD80D572380C0F700B9C227 /* UninstallPlugin.sh in Resources */,
BF458694229872EA00BD7491 /* Assets.xcassets in Resources */,
BF458697229872EA00BD7491 /* Main.storyboard in Resources */,
BF4C7F27238086EB00B2556E /* InstallPlugin.sh in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 51;
objects = {
/* Begin PBXAggregateTarget section */
@@ -2211,7 +2211,7 @@
LastUpgradeCheck = 1100;
};
buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 10.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -2532,45 +2532,6 @@
};
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 */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3A44D4EBF7CD579B73B275F0F125F846 /* Pods-AltServer.debug.xcconfig */;
@@ -2843,45 +2804,6 @@
};
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 */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5B1BF3395506426B10A06E5307D1EEFA /* Sparkle.xcconfig */;
@@ -3044,6 +2966,44 @@
};
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 */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1215053FA027E4CE849DAF4D00697FF1 /* Pods-AltServer.release.xcconfig */;
@@ -3085,6 +3045,44 @@
};
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 */
/* Begin XCConfigurationList section */
@@ -3118,8 +3116,8 @@
54208ED19403AA500F1198EEF237E880 /* Build configuration list for PBXNativeTarget "STPrivilegedTask" */ = {
isa = XCConfigurationList;
buildConfigurations = (
01FC26EF7492A83715733D6E82B58E10 /* Debug */,
569B2F7FFE1A40245840B5BD14E5075B /* Release */,
F53E3123D6E0B1A60F1DFB065889DFD7 /* Debug */,
DAA2BB16DE5BB8A33D1F4FEBC5F6E540 /* Release */,
);
defaultConfigurationIsVisible = 0;
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
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
// Create task
STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init];
[privilegedTask setLaunchPath:@"/usr/bin/touch"];
NSArray *args = [NSArray arrayWithObject:@"/etc/my_test_file"];
[privilegedTask setArguments:args];
[privilegedTask setCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];
[privilegedTask setArguments:@[@"/etc/my_test_file"]];
//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];
if (err != errAuthorizationSuccess) {
if (err == errAuthorizationCanceled) {
NSLog(@"User cancelled");
} else {
NSLog(@"Something went wrong");
}
if (err == errAuthorizationSuccess) {
NSLog(@"Task successfully launched");
}
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
NSFileHandle *readHandle = [privilegedTask outputFileHandle];
NSData *outputData = [readHandle readDataToEndOfFile];
NSData *outputData = [[privilegedTask outputFileHandle] readDataToEndOfFile];
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
# 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.
### Task termination
```
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
# Copyright (C) 2009-2015 Sveinbjorn Thordarson <sveinbjornt@gmail.com>
# Copyright (C) 2009-2017 Sveinbjorn Thordarson <sveinbjorn@sveinbjorn.org>
#
# BSD License
# Redistribution and use in source and binary forms, with or without
@@ -11,7 +10,7 @@
# * 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
# * Neither the name of the copyright holder nor that of any other
# contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
@@ -28,54 +27,43 @@
*/
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
#define STPrivilegedTaskDidTerminateNotification @"STPrivilegedTaskDidTerminateNotification"
//#define TMP_STDERR_TEMPLATE @".authStderr.XXXXXX"
// Defines error value for when AuthorizationExecuteWithPrivilleges no longer
// exists anyplace. Rather than defining a new enum, we just create a global
// constant
// Defines error value for when AuthorizationExecuteWithPrivileges no longer exists
// Rather than defining a new enum, we just create a global constant
extern const OSStatus errAuthorizationFnNoLongerExists;
@interface STPrivilegedTask : NSObject
{
NSArray *arguments;
NSString *cwd;
NSString *launchPath;
BOOL isRunning;
pid_t pid;
int terminationStatus;
NSFileHandle *outputFileHandle;
NSTimer *checkStatusTimer;
}
-(id)initWithLaunchPath:(NSString *)path;
-(id)initWithLaunchPath:(NSString *)path arguments: (NSArray *)args;
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path;
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;
-(NSArray *)arguments;
-(NSString *)currentDirectoryPath;
-(BOOL)isRunning;
-(int)launch;
-(NSString *)launchPath;
-(int)processIdentifier;
-(void)setArguments:(NSArray *)arguments;
-(void)setCurrentDirectoryPath:(NSString *)path;
-(void)setLaunchPath:(NSString *)path;
-(NSFileHandle *)outputFileHandle;
-(void)terminate; // doesn't work
-(int)terminationStatus;
-(void)_checkTaskStatus;
-(void)waitUntilExit;
@interface STPrivilegedTask : NSObject
@property (copy) NSArray *arguments;
@property (copy) NSString *currentDirectoryPath;
@property (copy) NSString *launchPath;
@property (assign) BOOL freeAuthorizationWhenDone;
@property (readonly) NSFileHandle *outputFileHandle;
@property (readonly) BOOL isRunning;
@property (readonly) pid_t processIdentifier;
@property (readonly) int terminationStatus;
@property (readonly) AuthorizationRef authorization;
@property (copy) void (^terminationHandler)(STPrivilegedTask *);
+ (BOOL)authorizationFunctionAvailable;
- (instancetype)initWithLaunchPath:(NSString *)path;
- (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args;
- (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd;
+ (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path;
+ (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args;
+ (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd;
+ (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd authorization:(AuthorizationRef)authorization;
- (OSStatus)launch;
- (OSStatus)launchWithAuthorization:(AuthorizationRef)authorization;
- (void)terminate; // doesn't work
- (void)waitUntilExit;
@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
# Copyright (C) 2009-2015 Sveinbjorn Thordarson <sveinbjornt@gmail.com>
# Copyright (C) 2009-2017 Sveinbjorn Thordarson <sveinbjorn@sveinbjorn.org>
#
# BSD License
# Redistribution and use in source and binary forms, with or without
@@ -11,7 +10,7 @@
# * 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
# * Neither the name of the copyright holder nor that of any other
# contributors may be used to endorse or promote products
# 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
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
*/
#import "STPrivilegedTask.h"
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
#import <stdio.h>
#import <unistd.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;
// 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
- (id)init
{
if ((self = [super init])) {
launchPath = @"";
cwd = [[NSString alloc] initWithString:[[NSFileManager defaultManager] currentDirectoryPath]];
arguments = [[NSArray alloc] init];
isRunning = NO;
outputFileHandle = nil;
NSTimer *_checkStatusTimer;
}
+ (void)initialize;
{
// 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;
}
-(void)dealloc
- (instancetype)initWithLaunchPath:(NSString *)path
{
#if !__has_feature(objc_arc)
[launchPath release];
[arguments release];
[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];
self = [self init];
if (self) {
self.launchPath = path;
}
return self;
}
-(id)initWithLaunchPath:(NSString *)path
- (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args
{
if ((self = [self init])) {
[self setLaunchPath:path];
self = [self initWithLaunchPath:path];
if (self) {
self.arguments = args;
}
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 -
+(STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args
{
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 *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path
{
STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path];
#if !__has_feature(objc_arc)
[task autorelease];
#endif
[task launch];
[task waitUntilExit];
return task;
}
#pragma mark -
- (NSArray *)arguments
+ (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args
{
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;
}
- (NSString *)launchPath
{
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;
STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args currentDirectory:cwd];
[task launchWithAuthorization:authorization];
[task waitUntilExit];
return task;
}
# pragma mark -
// 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;
const char *toolPath = [launchPath fileSystemRepresentation];
const char *toolPath = [self.launchPath fileSystemRepresentation];
AuthorizationRef authorizationRef;
AuthorizationItem myItems = {kAuthorizationRightExecute, strlen(toolPath), &toolPath, 0};
AuthorizationRights myRights = {1, &myItems};
AuthorizationItem myItems = { kAuthorizationRightExecute, strlen(toolPath), &toolPath, 0 };
AuthorizationRights myRights = { 1, &myItems };
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
// 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.
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
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
for (int i = 0; i < numberOfArguments; 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));
snprintf(args[i], stringLength + 1, "%s", [argString fileSystemRepresentation]);
snprintf(args[i], stringLength + 1, "%s", fsrep);
}
args[numberOfArguments] = NULL;
// change to the current dir specified
char *prevCwd = (char *)getcwd(nil, 0);
chdir([cwd fileSystemRepresentation]);
chdir([self.currentDirectoryPath fileSystemRepresentation]);
//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
chdir(prevCwd);
@@ -254,208 +242,92 @@ OSStatus const errAuthorizationFnNoLongerExists = -70001;
free(args[i]);
}
// free the auth ref
AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
// we return err if execution failed
if (err != errAuthorizationSuccess) {
return err;
} else {
isRunning = YES;
_isRunning = YES;
}
// get file handle for the command output
outputFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(outputFile) closeOnDealloc:YES];
pid = fcntl(fileno(outputFile), F_GETOWN, 0);
_outputFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(outputFile) closeOnDealloc:YES];
_processIdentifier = fcntl(fileno(outputFile), F_GETOWN, 0);
// 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;
}
- (void)terminate
{
// This doesn't work without a PID, and we can't get one. Stupid Security API
/* int ret = kill(pid, SIGKILL);
if (ret != 0)
NSLog(@"Error %d", errno);*/
// This doesn't work without a PID, and we can't get one. Stupid Security API.
// int ret = kill(pid, SIGKILL);
//
// if (ret != 0) {
// NSLog(@"Error %d", errno);
// }
}
// hang until task is done
- (void)waitUntilExit
{
waitpid([self processIdentifier], &terminationStatus, 0);
isRunning = NO;
if (!_isRunning) {
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 privileged task is still running
- (void)_checkTaskStatus
{
// see if task has terminated
int mypid = waitpid([self processIdentifier], &terminationStatus, WNOHANG);
if (mypid != 0) {
isRunning = NO;
// check if task has terminated
- (void)checkTaskStatus
{
int status;
pid_t pid = waitpid(_processIdentifier, &status, WNOHANG);
if (pid != 0) {
_isRunning = NO;
_terminationStatus = WEXITSTATUS(status);
[_checkStatusTimer invalidate];
[[NSNotificationCenter defaultCenter] postNotificationName:STPrivilegedTaskDidTerminateNotification object:self];
[checkStatusTimer invalidate];
if (_terminationHandler) {
_terminationHandler(self);
}
}
}
#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
{
NSArray *args = [self arguments];
NSString *cmd = [[self launchPath] copy];
NSString *commandDescription = [NSString stringWithString:self.launchPath];
for (int i = 0; i < [args count]; i++) {
cmd = [cmd stringByAppendingFormat:@" %@", args[i]];
for (NSString *arg in self.arguments) {
commandDescription = [commandDescription stringByAppendingFormat:@" '%@'", arg];
}
[commandDescription stringByAppendingFormat:@" (CWD:%@)", self.currentDirectoryPath];
return [[super description] stringByAppendingFormat:@" %@", cmd];
return [[super description] stringByAppendingFormat:@" %@", commandDescription];
}
@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
# 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.
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.
## Sparkle

View File

@@ -14,28 +14,35 @@
</dict>
<dict>
<key>FooterText</key>
<string> # 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.
<string>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.
</string>
<key>License</key>
<string>BSD</string>

View File

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