Bug 1728167: Add ability for standard users to install from a DMG through elevation. r=mstange,application-update-reviewers,bytesized

Differential Revision: https://phabricator.services.mozilla.com/D123899
This commit is contained in:
Stephen A Pohl 2021-09-03 20:41:31 +00:00
parent 86fc7a1397
commit c494ddeedd
6 changed files with 1081 additions and 936 deletions

View File

@ -450,3 +450,59 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
}
}
}
#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
@interface NSTask (NSTask10_13)
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
@property(copy) NSArray<NSString*>* arguments;
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
@end
#endif
/**
* Helper to launch macOS tasks via NSTask.
*/
static void LaunchTask(NSString* aPath, NSArray* aArguments) {
if (@available(macOS 10.13, *)) {
NSTask* task = [[NSTask alloc] init];
[task setExecutableURL:[NSURL fileURLWithPath:aPath]];
if (aArguments) {
[task setArguments:aArguments];
}
[task launchAndReturnError:nil];
[task release];
} else {
NSArray* arguments = aArguments;
if (!arguments) {
arguments = @[];
}
[NSTask launchedTaskWithLaunchPath:aPath arguments:arguments];
}
}
static void RegisterAppWithLaunchServices(NSString* aBundlePath) {
NSArray* arguments = @[ @"-f", aBundlePath ];
LaunchTask(@"/System/Library/Frameworks/CoreServices.framework/Frameworks/"
@"LaunchServices.framework/Support/lsregister",
arguments);
}
static void StripQuarantineBit(NSString* aBundlePath) {
NSArray* arguments = @[ @"-d", @"com.apple.quarantine", aBundlePath ];
LaunchTask(@"/usr/bin/xattr", arguments);
}
bool PerformInstallationFromDMG(int argc, char** argv) {
MacAutoreleasePool pool;
if (argc < 4) {
return false;
}
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
NSString* destPath = [NSString stringWithUTF8String:argv[3]];
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:destPath error:nil]) {
RegisterAppWithLaunchServices(destPath);
StripQuarantineBit(destPath);
return true;
}
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
#include <sys/param.h>
#include "MacRunFromDmgUtils.h"
#include "MacLaunchHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/intl/Localization.h"
@ -25,19 +26,13 @@
#include "nsIMacDockSupport.h"
#include "nsObjCExceptions.h"
#include "nsString.h"
#include "nsUpdateDriver.h"
#include "SDKDeclarations.h"
// For IOKit docs, see:
// https://developer.apple.com/documentation/iokit
// https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/
#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
@interface NSTask (NSTask10_13)
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
@property(copy) NSArray<NSString*>* arguments;
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
@end
#endif
namespace mozilla {
namespace MacRunFromDmgUtils {
@ -178,11 +173,41 @@ static void StripQuarantineBit(NSString* aBundlePath) {
LaunchTask(@"/usr/bin/xattr", arguments);
}
bool LaunchElevatedDmgInstall(NSString* aBundlePath, NSArray* aArguments) {
NSTask* task;
if (@available(macOS 10.13, *)) {
task = [[NSTask alloc] init];
[task setExecutableURL:[NSURL fileURLWithPath:aBundlePath]];
if (aArguments) {
[task setArguments:aArguments];
}
[task launchAndReturnError:nil];
} else {
NSArray* arguments = aArguments;
if (!arguments) {
arguments = @[];
}
task = [NSTask launchedTaskWithLaunchPath:aBundlePath arguments:arguments];
}
bool didSucceed = InstallPrivilegedHelper();
[task waitUntilExit];
if (@available(macOS 10.13, *)) {
[task release];
}
if (!didSucceed) {
AbortElevatedUpdate();
}
return didSucceed;
}
// Note: both arguments are expected to contain the app name (to end with
// '.app').
static bool InstallFromDmg(NSString* aBundlePath, NSString* aDestPath) {
bool installSuccessful = false;
if ([[NSFileManager defaultManager] copyItemAtPath:aBundlePath toPath:aDestPath error:nil]) {
NSFileManager* fileManager = [NSFileManager defaultManager];
if ([fileManager copyItemAtPath:aBundlePath toPath:aDestPath error:nil]) {
RegisterAppWithLaunchServices(aDestPath);
StripQuarantineBit(aDestPath);
installSuccessful = true;
@ -190,10 +215,22 @@ static bool InstallFromDmg(NSString* aBundlePath, NSString* aDestPath) {
// The installation may have been unsuccessful if the user did not have the
// rights to write to the Applications directory. Check for this situation and
// launch an elevated installation if necessary.
// launch an elevated installation if necessary. Rather than creating a new,
// dedicated executable for this installation and incurring the
// added maintenance burden of yet another executable, we are using the
// updater binary. Since bug 394984 landed, the updater has the ability to
// install and launch itself as a Privileged Helper tool, which is what is
// necessary here.
NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
if (!installSuccessful && ![[NSFileManager defaultManager] isWritableFileAtPath:destDir]) {
// TODO: launch elevated installation.
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
NSString* updaterBinPath = [NSString pathWithComponents:@[
aBundlePath, @"Contents", @"MacOS", [NSString stringWithUTF8String:UPDATER_APP], @"Contents",
@"MacOS", [NSString stringWithUTF8String:UPDATER_BIN]
]];
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
LaunchElevatedDmgInstall(updaterBinPath, arguments);
installSuccessful = [fileManager fileExistsAtPath:aDestPath];
}
if (!installSuccessful) {

View File

@ -64,16 +64,6 @@ static LazyLogModule sUpdateLog("updatedriver");
#endif
#define LOG(args) MOZ_LOG(sUpdateLog, mozilla::LogLevel::Debug, args)
#ifdef XP_WIN
# define UPDATER_BIN "updater.exe"
# define MAINTENANCE_SVC_NAME L"MozillaMaintenance"
#elif XP_MACOSX
# define UPDATER_APP "updater.app"
# define UPDATER_BIN "org.mozilla.updater"
#else
# define UPDATER_BIN "updater"
#endif
#ifdef XP_MACOSX
static void UpdateDriverSetupMacCommandLine(int& argc, char**& argv,
bool restart) {

View File

@ -26,6 +26,16 @@ typedef pid_t ProcessType;
typedef PRProcess* ProcessType;
#endif
#ifdef XP_WIN
# define UPDATER_BIN "updater.exe"
# define MAINTENANCE_SVC_NAME L"MozillaMaintenance"
#elif XP_MACOSX
# define UPDATER_APP "updater.app"
# define UPDATER_BIN "org.mozilla.updater"
#else
# define UPDATER_BIN "updater"
#endif
/**
* This function processes any available updates. As part of that process, it
* may exit the current process and relaunch it at a later time.

View File

@ -30,6 +30,12 @@ using NSAppearanceName = NSString*;
@property(class, strong, readonly) NSColor* systemPurpleColor NS_AVAILABLE_MAC(10_10);
@end
@interface NSTask (NSTask10_13)
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
@property(copy) NSArray<NSString*>* arguments;
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
@end
#endif
#if !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14