Bug 711475: Allow to perform updates using the About Firefox dialog on limited user accounts if the maintenance service is installed. r=bbondy

This commit is contained in:
Steffen Wilberg 2013-08-07 23:07:17 +02:00
parent 64c48d0661
commit 8ed68047a0
2 changed files with 105 additions and 66 deletions

View File

@ -424,8 +424,10 @@ interface nsIApplicationUpdateService : nsISupports
/**
* Whether or not the Update Service can download and install updates.
* This is a function of whether or not the current user has access
* privileges to the install directory.
* On Windows, this is a function of whether or not the maintenance service
* is installed and enabled. On other systems, and as a fallback on Windows,
* this depends on whether the current user has write access to the install
* directory.
*/
readonly attribute boolean canApplyUpdates;

View File

@ -572,52 +572,61 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
}
}
try {
var updateTestFile = getUpdateFile([FILE_PERMS_TEST]);
LOG("gCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false);
let useService = false;
if (shouldUseService() && isServiceInstalled()) {
// No need to perform directory write checks, the maintenance service will
// be able to write to all directories.
LOG("gCanApplyUpdates - bypass the write checks because we'll use the service");
useService = true;
}
if (!useService) {
try {
var updateTestFile = getUpdateFile([FILE_PERMS_TEST]);
LOG("gCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false);
#ifdef XP_WIN
var sysInfo = Cc["@mozilla.org/system-info;1"].
getService(Ci.nsIPropertyBag2);
var sysInfo = Cc["@mozilla.org/system-info;1"].
getService(Ci.nsIPropertyBag2);
// Example windowsVersion: Windows XP == 5.1
var windowsVersion = sysInfo.getProperty("version");
LOG("gCanApplyUpdates - windowsVersion = " + windowsVersion);
/**
# For Vista, updates can be performed to a location requiring admin
# privileges by requesting elevation via the UAC prompt when launching
# updater.exe if the appDir is under the Program Files directory
# (e.g. C:\Program Files\) and UAC is turned on and we can elevate
# (e.g. user has a split token).
#
# Note: this does note attempt to handle the case where UAC is turned on
# and the installation directory is in a restricted location that
# requires admin privileges to update other than Program Files.
*/
var userCanElevate = false;
if (parseFloat(windowsVersion) >= 6) {
try {
var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
// KEY_UPDROOT will fail and throw an exception if
// appDir is not under the Program Files, so we rely on that
var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile);
// appDir is under Program Files, so check if the user can elevate
userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
userCanElevate;
LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
}
catch (ex) {
// When the installation directory is not under Program Files,
// fall through to checking if write access to the
// installation directory is available.
LOG("gCanApplyUpdates - on Vista, appDir is not under Program Files");
}
}
// Example windowsVersion: Windows XP == 5.1
var windowsVersion = sysInfo.getProperty("version");
LOG("gCanApplyUpdates - windowsVersion = " + windowsVersion);
/**
# For Vista, updates can be performed to a location requiring admin
# privileges by requesting elevation via the UAC prompt when launching
# updater.exe if the appDir is under the Program Files directory
# (e.g. C:\Program Files\) and UAC is turned on and we can elevate
# (e.g. user has a split token).
#
# Note: this does note attempt to handle the case where UAC is turned on
# and the installation directory is in a restricted location that
# requires admin privileges to update other than Program Files.
*/
var userCanElevate = false;
if (parseFloat(windowsVersion) >= 6) {
try {
var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
// KEY_UPDROOT will fail and throw an exception if
// appDir is not under the Program Files, so we rely on that
var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile);
// appDir is under Program Files, so check if the user can elevate
userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
userCanElevate;
LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
}
catch (ex) {
// When the installation directory is not under Program Files,
// fall through to checking if write access to the
// installation directory is available.
LOG("gCanApplyUpdates - on Vista, appDir is not under Program Files");
}
}
/**
# On Windows, we no longer store the update under the app dir.
#
# If we are on Windows (including Vista, if we can't elevate) we need to
@ -636,25 +645,26 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
# (e.g. the user does not have a split token)
# 4) UAC is turned on and the user is already elevated, so they can't be
# elevated again
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
var appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_PERMS_TEST);
LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists())
appDirTestFile.remove(false)
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
*/
if (!userCanElevate) {
// if we're unable to create the test file this will throw an exception.
var appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_PERMS_TEST);
LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists())
appDirTestFile.remove(false)
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
}
#endif //XP_WIN
}
catch (e) {
LOG("gCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
submitHasPermissionsTelemetryPing(false);
return false;
}
}
catch (e) {
LOG("gCanApplyUpdates - unable to apply updates. Exception: " + e);
// No write privileges to install directory
submitHasPermissionsTelemetryPing(false);
return false;
}
} // if (!useService)
if (!hasUpdateMutex()) {
LOG("gCanApplyUpdates - unable to apply updates because another instance" +
@ -1116,6 +1126,33 @@ function shouldUseService() {
#endif
}
/**
* Determines if the service is is installed and enabled or not.
*
* @return true if the service should be used for updates,
* is installed and enabled.
*/
function isServiceInstalled() {
#ifdef XP_WIN
let installed = 0;
try {
let wrk = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Mozilla\\MaintenanceService",
wrk.ACCESS_READ | wrk.WOW64_64);
installed = wrk.readIntValue("Installed");
wrk.close();
} catch(e) {
}
installed = installed == 1; // convert to bool
LOG("isServiceInstalled = " + installed);
return installed;
#else
return false;
#endif
}
/**
# Writes the update's application version to a file in the patch directory. If
# the update doesn't provide application version information via the
@ -2243,7 +2280,7 @@ UpdateService.prototype = {
* service was at some point installed, but is now uninstalled.
*/
_sendServiceInstalledTelemetryPing: function AUS__svcInstallTelemetryPing() {
let installed = 0;
let installed = isServiceInstalled(); // Is the service installed?
let attempted = 0;
try {
let wrk = Cc["@mozilla.org/windows-registry-key;1"].
@ -2251,14 +2288,14 @@ UpdateService.prototype = {
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Mozilla\\MaintenanceService",
wrk.ACCESS_READ | wrk.WOW64_64);
// Was the service at some point installed, but is now uninstalled?
attempted = wrk.readIntValue("Attempted");
installed = wrk.readIntValue("Installed");
wrk.close();
} catch(e) {
}
try {
let h = Services.telemetry.getHistogramById("UPDATER_SERVICE_INSTALLED");
h.add(installed);
h.add(Number(installed));
} catch(e) {
// Don't allow any exception to be propagated.
Cu.reportError(e);
@ -4270,7 +4307,7 @@ Downloader.prototype = {
"max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout);
if (Components.isSuccessCode(status)) {
if (this._verifyDownload()) {
state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING
state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING;
if (this.background) {
shouldShowPrompt = !getCanStageUpdates();
}