Bug 407875 - "Unprivileged users are not notified of security updates" [r=Mossop a=beltzner]
authorRobert Strong <robert.bugzilla@gmail.com>
Tue, 01 Dec 2009 15:35:00 -0600
changeset 26890 b9e025a5f582f00c89188d6fb6aeed177a2ece70
parent 26889 9c4e273fb2917009d0c1a39d5560bb5d48983694
child 26891 a2f5c0776892d9ffdd7ef42b5720131623423058
push id2349
push userreed@reedloden.com
push dateTue, 13 Apr 2010 05:48:34 +0000
reviewersMossop, beltzner
bugs407875
milestone1.9.1.10pre
Bug 407875 - "Unprivileged users are not notified of security updates" [r=Mossop a=beltzner]
browser/base/content/utilityOverlay.js
browser/components/preferences/advanced.js
other-licenses/branding/firefox/pref/firefox-branding.js
toolkit/mozapps/update/content/updates.js
toolkit/mozapps/update/content/updates.xul
toolkit/mozapps/update/public/nsIUpdateService.idl
toolkit/mozapps/update/src/nsUpdateService.js.in
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -474,27 +474,27 @@ function buildHelpMenu()
   // Enable/disable the "Report Web Forgery" menu item.  safebrowsing object
   // may not exist in OSX
   if (typeof safebrowsing != "undefined")
     safebrowsing.setReportPhishingMenu();
 
 #ifdef MOZ_UPDATER
   var updates = 
       Components.classes["@mozilla.org/updates/update-service;1"].
-      getService(Components.interfaces.nsIApplicationUpdateService);
+      getService(Components.interfaces.nsIApplicationUpdateService2);
   var um = 
       Components.classes["@mozilla.org/updates/update-manager;1"].
       getService(Components.interfaces.nsIUpdateManager);
 
   // Disable the UI if the update enabled pref has been locked by the 
   // administrator or if we cannot update for some other reason
   var checkForUpdates = document.getElementById("checkForUpdates");
-  var canUpdate = updates.canUpdate;
-  checkForUpdates.setAttribute("disabled", !canUpdate);
-  if (!canUpdate)
+  var canCheckForUpdates = updates.canCheckForUpdates;
+  checkForUpdates.setAttribute("disabled", !canCheckForUpdates);
+  if (!canCheckForUpdates)
     return; 
 
   var strings = document.getElementById("bundle_browser");
   var activeUpdate = um.activeUpdate;
   
   // If there's an active update, substitute its name into the label
   // we show for this item, otherwise display a generic label.
   function getStringWithUpdateName(key) {
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -398,22 +398,22 @@ var gAdvancedPane = {
    *             iii 0/1/2   t         true   
    * 
    */
 #ifdef MOZ_UPDATER
   updateAppUpdateItems: function () 
   {
     var aus = 
         Components.classes["@mozilla.org/updates/update-service;1"].
-        getService(Components.interfaces.nsIApplicationUpdateService);
+        getService(Components.interfaces.nsIApplicationUpdateService2);
 
     var enabledPref = document.getElementById("app.update.enabled");
     var enableAppUpdate = document.getElementById("enableAppUpdate");
 
-    enableAppUpdate.disabled = !aus.canUpdate || enabledPref.locked;
+    enableAppUpdate.disabled = !aus.canCheckForUpdates || enabledPref.locked;
   },
 
   /**
    * Enables/disables UI for "when updates are found" based on the values,
    * and "locked" states of associated preferences.
    */
   updateAutoItems: function () 
   {
--- a/other-licenses/branding/firefox/pref/firefox-branding.js
+++ b/other-licenses/branding/firefox/pref/firefox-branding.js
@@ -1,16 +1,16 @@
 pref("startup.homepage_override_url","http://%LOCALE%.www.mozilla.com/%LOCALE%/%APP%/%VERSION%/whatsnew/");
 pref("startup.homepage_welcome_url","http://%LOCALE%.www.mozilla.com/%LOCALE%/%APP%/%VERSION%/firstrun/");
 // Interval: Time between checks for a new version (in seconds)
 // nightly=6 hours, official=24 hours
 pref("app.update.interval", 86400);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
-pref("app.update.url.manual", "http://%LOCALE%.www.mozilla.com/%LOCALE%/%APP%/");
+pref("app.update.url.manual", "http://www.firefox.com");
 // A default value for the "More information about this update" link
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "http://%LOCALE%.www.mozilla.com/%LOCALE%/%APP%/releases/");
 
 // Release notes URL
 pref("app.releaseNotesURL", "http://%LOCALE%.www.mozilla.com/%LOCALE%/%APP%/%VERSION%/releasenotes/");
 
 pref("browser.search.param.yahoo-fr", "moz35");
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -217,17 +217,17 @@ var gUpdates = {
   never: function () {
     // If the user clicks "Never", we should not prompt them about updating to
     // this major update version again, unless they manually do
     // "Check for Updates..." which will clear the "never" pref for the version
     // presented and remind them later about this available update.
     //
     // Encode version since it could be a non-ascii string (bug 359093)
     var neverPrefName = PREF_UPDATE_NEVER_BRANCH +
-                       encodeURIComponent(gUpdates.update.version);
+                        encodeURIComponent(gUpdates.update.version);
     gPref.setBoolPref(neverPrefName, true);
     this.wiz.cancel();
   },
 
   later: function () {
     // The user said "Later", so close the wizard
     this.wiz.cancel();
   },
@@ -583,16 +583,25 @@ var gIncompatibleCheckPage = {
    * The progress bar for this page
    */
   _pBar: null,
 
   /**
    * Initialize
    */
   onPageShow: function() {
+    var aus = CoC["@mozilla.org/updates/update-service;1"].
+              getService(CoI.nsIApplicationUpdateService2);
+    // Display the manual update page if the user is unable to apply the update
+    if (!aus.canApplyUpdates) {
+      gUpdates.wiz.currentPage.setAttribute("next", "manualUpdate");
+      gUpdates.wiz.advance();
+      return;
+    }
+
     var ai = CoC["@mozilla.org/xre/app-info;1"].getService(CoI.nsIXULAppInfo);
     var vc = CoC["@mozilla.org/xpcom/version-comparator;1"].
              getService(CoI.nsIVersionComparator);
     if (!gUpdates.update.extensionVersion ||
         vc.compare(gUpdates.update.extensionVersion, ai.version) == 0) {
       // Go to the next page
       gUpdates.wiz.advance();
       return;
@@ -700,16 +709,41 @@ var gIncompatibleCheckPage = {
     if (!iid.equals(CoI.nsIAddonUpdateCheckListener) &&
         !iid.equals(CoI.nsISupports))
       throw CoR.NS_ERROR_NO_INTERFACE;
     return this;
   }
 };
 
 /**
+ * The "Unable to Update" page. Provides the user information about why they
+ * were unable to update and a manual download url.
+ */
+var gManualUpdatePage = {
+  onPageShow: function() {
+    var formatter = CoC["@mozilla.org/toolkit/URLFormatterService;1"].
+                    getService(CoI.nsIURLFormatter);
+    var manualURL = formatter.formatURLPref(PREF_UPDATE_MANUAL_URL);
+    var manualUpdateLinkLabel = document.getElementById("manualUpdateLinkLabel");
+    manualUpdateLinkLabel.value = manualURL;
+    manualUpdateLinkLabel.setAttribute("url", manualURL);
+
+    // Prevent multiple notifications for the same update when the user is
+    // unable to apply updates.
+    // Encode version since it could be a non-ascii string (bug 359093)
+    var neverPrefName = PREF_UPDATE_NEVER_BRANCH +
+                        encodeURIComponent(gUpdates.update.version);
+    gPref.setBoolPref(neverPrefName, true);
+
+    gUpdates.setButtons(null, null, "okButton", true);
+    gUpdates.wiz.getButton("finish").focus();
+  }
+};
+
+/**
  * The "Updates Are Available" page. Provides the user information about the
  * available update.
  */
 var gUpdatesAvailablePage = {
   /**
    * If this page has been previously loaded
    */
   _loaded: false,
--- a/toolkit/mozapps/update/content/updates.xul
+++ b/toolkit/mozapps/update/content/updates.xul
@@ -91,16 +91,28 @@
               next="updatesfound" label="&incompatibleCheck.title;"
               object="gIncompatibleCheckPage"
               onpageshow="gIncompatibleCheckPage.onPageShow();">
     <label>&incompatibleCheck.label;</label>
     <separator class="thin"/>
     <progressmeter id="incompatibleCheckProgress" mode="undetermined" hidden="true"/>
   </wizardpage>
 
+  <wizardpage id="manualUpdate" pageid="manualUpdate"
+              label="&manualUpdate.title;" object="gManualUpdatePage"
+              onpageshow="gManualUpdatePage.onPageShow();">
+    <description>&manualUpdate.desc;</description>
+    <separator class="thin"/>
+    <label>&manualUpdateGetMsg.label;</label>
+    <hbox>
+      <label class="text-link" id="manualUpdateLinkLabel" value=""
+             onclick="openUpdateURL(event);"/>
+    </hbox>
+  </wizardpage>
+
   <wizardpage id="updatesfound" pageid="updatesfound" next="license"
               object="gUpdatesAvailablePage" label=""
               onpageshow="gUpdatesAvailablePage.onPageShow();"
               onextra1="gUpdatesAvailablePage.onExtra1();"
               onextra2="gUpdatesAvailablePage.onExtra2();">
     <description id="updateType"/>
     <separator class="thin"/>
     <label id="updateName" crop="right" value=""/>
--- a/toolkit/mozapps/update/public/nsIUpdateService.idl
+++ b/toolkit/mozapps/update/public/nsIUpdateService.idl
@@ -400,16 +400,39 @@ interface nsIApplicationUpdateService : 
    * 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.
    */
   readonly attribute boolean canUpdate;
 };
 
 /**
+ * A temporary interface to allow adding new methods without changing existing
+ * interfaces for Gecko 1.9.1 and 1.9.2. After the 1.9.2 release this interface
+ * will be removed.
+ */
+[scriptable, uuid(e22e4bf1-b18c-40cd-a2be-2d565723d056)]
+interface nsIApplicationUpdateService2 : nsIApplicationUpdateService
+{
+  /**
+   * Whether or not the Update Service can check for updates. This is a function
+   * of whether or not application update is disabled by the application and the
+   * platform the application is running on.
+   */
+  readonly attribute boolean canCheckForUpdates;
+
+  /**
+   * 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.
+   */
+  readonly attribute boolean canApplyUpdates;
+};
+
+/**
  * An interface describing a global application service that maintains a list
  * of updates previously performed as well as the current active update.
  */
 [scriptable, uuid(fede66a9-9f96-4507-a22a-775ee885577e)]
 interface nsIUpdateManager : nsISupports
 {
   /**
    * Gets the update at the specified index
--- a/toolkit/mozapps/update/src/nsUpdateService.js.in
+++ b/toolkit/mozapps/update/src/nsUpdateService.js.in
@@ -124,17 +124,16 @@ const TOOLKIT_ID              = "toolkit
 const POST_UPDATE_CONTRACTID = "@mozilla.org/updates/post-update;1";
 
 var gApp        = null;
 var gPref       = null;
 var gABI        = null;
 var gOSVersion  = null;
 var gLocale     = null;
 var gConsole    = null;
-var gCanUpdate  = null;
 var gLogEnabled = { };
 
 // shared code for suppressing bad cert dialogs
 #include ../../shared/src/badCertHandler.js
 
 /**
  * Logs a string to the error console.
  * @param   string
@@ -144,16 +143,153 @@ function LOG(module, string) {
   if (module in gLogEnabled || "all" in gLogEnabled) {
     dump("*** AUS:SVC " + module + ":" + string + "\n");
     // On startup gConsole may not be initialized
     if (gConsole)
       gConsole.logStringMessage("AUS:SVC " + module + ":" + string);
   }
 }
 
+__defineGetter__("gCanCheckForUpdates", function () {
+  delete this.gCanCheckForUpdates;
+  // If the administrator has locked the app update functionality
+  // OFF - this is not just a user setting, so disable the manual
+  // UI too.
+  var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true);
+  if (!enabled && gPref.prefIsLocked(PREF_APP_UPDATE_ENABLED)) {
+    LOG("UpdateService", "gCanCheckForUpdates - unable to check for " +
+        "updates, disabled by pref");
+    return gCanCheckForUpdates = false;
+  }
+
+  // If we don't know the binary platform we're updating, we can't update.
+  if (!gABI) {
+    LOG("UpdateService", "gCanCheckForUpdates - unable to check for " +
+        "updates, unknown ABI");
+    return gCanCheckForUpdates = false;
+  }
+
+  // If we don't know the OS version we're updating, we can't update.
+  if (!gOSVersion) {
+    LOG("UpdateService", "gCanCheckForUpdates - unable to check for " +
+        "updates, unknown OS version");
+    return gCanCheckForUpdates = false;
+  }
+
+  LOG("UpdateService", "gCanCheckForUpdates - able to check for updates");
+  return gCanCheckForUpdates = true;
+});
+
+__defineGetter__("gCanApplyUpdates", function () {
+  delete this.gCanApplyUpdates;
+  try {
+    var appDirFile = getUpdateFile([FILE_PERMS_TEST]);
+    LOG("UpdateService", "gCanApplyUpdates - testing " + appDirFile.path);
+    if (!appDirFile.exists()) {
+      appDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
+      appDirFile.remove(false);
+    }
+    var updateDir = getUpdatesDir();
+    var upDirFile = updateDir.clone();
+    upDirFile.append(FILE_PERMS_TEST);
+    LOG("UpdateService", "gCanApplyUpdates - testing " + upDirFile.path);
+    if (!upDirFile.exists()) {
+      upDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
+      upDirFile.remove(false);
+    }
+#ifdef XP_WIN
+    var sysInfo = Cc["@mozilla.org/system-info;1"].
+                  getService(Ci.nsIPropertyBag2);
+
+    // Example windowsVersion:  Windows XP == 5.1
+    var windowsVersion = sysInfo.getProperty("version");
+    LOG("UpdateService", "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 = gApp.QueryInterface(Ci.nsIWinAppHelper).
+                         userCanElevate;
+        LOG("UpdateService", "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("UpdateService", "gCanApplyUpdates - on Vista, appDir is not " +
+            "under Program Files");
+      }
+    }
+
+    // On Windows, we no longer store the update under the app dir
+    // if the app dir is under C:\Program Files.
+    //
+    // If we are on Windows (including Vista, if we can't elevate)
+    // we need to check that
+    // we can create and remove files from the actual app directory
+    // (like C:\Program Files\Mozilla Firefox).  If we can't
+    // (because this user is not an adminstrator, for example)
+    // canUpdate() should return false.
+    //
+    // For Vista, we perform this check to enable updating the 
+    // application when the user has write access to the installation 
+    // directory under the following scenarios:
+    // 1) the installation directory is not under Program Files 
+    //    (e.g. C:\Program Files)
+    // 2) UAC is turned off
+    // 3) UAC is turned on and the user is not an admin 
+    //    (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
+      // the code below will throw an exception 
+      var actualAppDir = getDir(KEY_APPDIR, []);
+      var actualAppDirFile = actualAppDir.clone();
+      actualAppDirFile.append(FILE_PERMS_TEST);
+      LOG("UpdateService", "gCanApplyUpdates - testing " +
+          actualAppDirFile.path);
+      if (!actualAppDirFile.exists()) {
+        actualAppDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
+        actualAppDirFile.remove(false);
+      }
+    }
+#endif
+  }
+  catch (e) {
+     LOG("UpdateService", "gCanApplyUpdates - unable to apply update. " +
+         "Exception: " + e);
+    // No write privileges to install directory
+    return gCanApplyUpdates = false;
+  }
+
+  LOG("UpdateService", "gCanCheckForUpdates - able to apply updates");
+  return gCanApplyUpdates = true;
+});
+
 /**
  * Convert a string containing binary values to hex.
  */
 function binaryToHex(input) {
   var result = "";
   for (var i = 0; i < input.length; ++i) {
     var hex = input.charCodeAt(i).toString(16);
     if (hex.length == 1)
@@ -1182,18 +1318,21 @@ UpdateService.prototype = {
    * from a previous browser session - either report install failures (and
    * optionally attempt to fetch a different version if appropriate) or
    * notify the user of install success.
    */
   _postUpdateProcessing: function AUS__postUpdateProcessing() {
     // Detect installation failures and notify
 
     // Bail out if we don't have appropriate permissions
-    if (!this.canUpdate)
+    if (!this.canUpdate) {
+      LOG("UpdateService:_postUpdateProcessing - unable to update");
       return;
+    }
+ 
 
     var status = readStatusFile(getUpdatesDir());
 
     // Make sure to cleanup after an update that failed for an unknown reason
     if (status == "null")
       status = null;
 
     var updRootKey = null;
@@ -1447,16 +1586,31 @@ UpdateService.prototype = {
 #         never receive the minor update or the minor update they notification.
 #      b) the never decision only applies to major updates. See bug 350636 for
 #         a scenario where this could potentially be an issue.
      */
 
     // Encode version since it could be a non-ascii string (bug 359093)
     var neverPrefName = PREF_UPDATE_NEVER_BRANCH +
                         encodeURIComponent(update.version);
+
+    if (!gCanApplyUpdates) {
+      if (getPref("getBoolPref", neverPrefName, false)) {
+        LOG("Checker", "_selectAndInstallUpdate - the user is unable to " +
+            "apply updates. Not prompting because the preference " +
+            neverPrefName + " is true");
+      }
+      else {
+        LOG("Checker", "_selectAndInstallUpdate - the user is unable to " +
+            "apply updates... prompting");
+        this._showPrompt(update);
+      }
+      return;
+    }
+
     if (update.type == "major" &&
         getPref("getBoolPref", neverPrefName, false)) {
       LOG("Checker", "_selectAndInstallUpdate - not prompting because this " +
           "is a major update and the preference " + neverPrefName + " is true");
       return;
     }
 
     /**
@@ -1597,17 +1751,17 @@ UpdateService.prototype = {
    */
   onUpdateStarted: function AUS_onUpdateStarted() {
   },
 
   /**
    * See nsIExtensionManager.idl
    */
   onUpdateEnded: function AUS_onUpdateEnded() {
-    if (this._incompatAddonsCount > 0) {
+    if (this._incompatAddonsCount > 0 || !gCanApplyUpdates) {
       LOG("Checker", "onUpdateEnded - prompting because there are " +
           "incompatible add-ons");
       this._showPrompt(this._update);
     }
     else {
       LOG("UpdateService", "onUpdateEnded - no need to show prompt, just " +
           "download the update");
       var status = this.downloadUpdate(this._update, true);
@@ -1649,139 +1803,31 @@ UpdateService.prototype = {
       this._backgroundChecker = new Checker();
     return this._backgroundChecker;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   get canUpdate() {
-    if (gCanUpdate !== null)
-      return gCanUpdate;
-
-    try {
-      var appDirFile = getUpdateFile([FILE_PERMS_TEST]);
-      LOG("UpdateService", "canUpdate - testing " + appDirFile.path);
-      if (!appDirFile.exists()) {
-        appDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
-        appDirFile.remove(false);
-      }
-      var updateDir = getUpdatesDir();
-      var upDirFile = updateDir.clone();
-      upDirFile.append(FILE_PERMS_TEST);
-      LOG("UpdateService", "canUpdate - testing " + upDirFile.path);
-      if (!upDirFile.exists()) {
-        upDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
-        upDirFile.remove(false);
-      }
-#ifdef XP_WIN
-      var sysInfo = Cc["@mozilla.org/system-info;1"].
-                    getService(Ci.nsIPropertyBag2);
-
-      // Example windowsVersion:  Windows XP == 5.1
-      var windowsVersion = sysInfo.getProperty("version");
-      LOG("UpdateService", "canUpdate - 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 = gApp.QueryInterface(Ci.nsIWinAppHelper).
-                           userCanElevate;
-          LOG("UpdateService", "canUpdate - 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("UpdateService", "canUpdate - on Vista, appDir is not under " +
-              "Program Files");
-        }
-      }
-
-      // On Windows, we no longer store the update under the app dir
-      // if the app dir is under C:\Program Files.
-      //
-      // If we are on Windows (including Vista, if we can't elevate)
-      // we need to check that
-      // we can create and remove files from the actual app directory
-      // (like C:\Program Files\Mozilla Firefox).  If we can't
-      // (because this user is not an adminstrator, for example)
-      // canUpdate() should return false.
-      //
-      // For Vista, we perform this check to enable updating the 
-      // application when the user has write access to the installation 
-      // directory under the following scenarios:
-      // 1) the installation directory is not under Program Files 
-      //    (e.g. C:\Program Files)
-      // 2) UAC is turned off
-      // 3) UAC is turned on and the user is not an admin 
-      //    (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
-        // the code below will throw an exception 
-        var actualAppDir = getDir(KEY_APPDIR, []);
-        var actualAppDirFile = actualAppDir.clone();
-        actualAppDirFile.append(FILE_PERMS_TEST);
-        LOG("UpdateService", "canUpdate - testing " + actualAppDirFile.path);
-        if (!actualAppDirFile.exists()) {
-          actualAppDirFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
-          actualAppDirFile.remove(false);
-        }
-      }
-#endif
-    }
-    catch (e) {
-       LOG("UpdateService", "canUpdate - unable to update. Exception: " + e);
-      // No write privileges to install directory
-      return gCanUpdate = false;
-    }
-    // If the administrator has locked the app update functionality
-    // OFF - this is not just a user setting, so disable the manual
-    // UI too.
-    var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true);
-    if (!enabled && gPref.prefIsLocked(PREF_APP_UPDATE_ENABLED)) {
-      LOG("UpdateService", "canUpdate - unable to update, disabled by pref");
-      return gCanUpdate = false;
-    }
-
-    // If we don't know the binary platform we're updating, we can't update.
-    if (!gABI) {
-      LOG("UpdateService", "canUpdate - unable tp update, unknown ABI");
-      return gCanUpdate = false;
-    }
-
-    // If we don't know the OS version we're updating, we can't update.
-    if (!gOSVersion) {
-      LOG("UpdateService", "canUpdate unable to update, unknown OS version");
-      return gCanUpdate = false;
-    }
-
-    LOG("UpdateService", "canUpdate - able to update");
-    return gCanUpdate = true;
+    return gCanApplyUpdates && gCanCheckForUpdates;
+  },
+
+  /**
+   * See nsIUpdateService.idl
+   */
+  get canCheckForUpdates() {
+    return gCanCheckForUpdates;
+  },
+
+  /**
+   * See nsIUpdateService.idl
+   */
+  get canApplyUpdates() {
+    return gCanApplyUpdates;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   addDownloadListener: function AUS_addDownloadListener(listener) {
     if (!this._downloader) {
       LOG("UpdateService", "addDownloadListener - no downloader!");
@@ -1849,28 +1895,31 @@ UpdateService.prototype = {
     return this._downloader && this._downloader.isBusy;
   },
 
   // nsIClassInfo
   flags: Ci.nsIClassInfo.SINGLETON,
   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
   getHelperForLanguage: function(language) null,
   getInterfaces: function AUS_getInterfaces(count) {
-    var interfaces = [Ci.nsIApplicationUpdateService, Ci.nsITimerCallback,
+    var interfaces = [Ci.nsIApplicationUpdateService,
+                      Ci.nsIApplicationUpdateService2,
+                      Ci.nsITimerCallback,
                       Ci.nsIObserver];
     count.value = interfaces.length;
     return interfaces;
   },
 
   classDescription: "Update Service",
   contractID: "@mozilla.org/updates/update-service;1",
   classID: Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
   _xpcom_categories: [{ category: "app-startup", service: true }],
   _xpcom_factory: UpdateServiceFactory,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIApplicationUpdateService,
+                                         Ci.nsIApplicationUpdateService2,
                                          Ci.nsIAddonUpdateCheckListener,
                                          Ci.nsITimerCallback,
                                          Ci.nsIObserver])
 };
 
 /**
  * A service to manage active and past updates.
  * @constructor
@@ -2304,21 +2353,18 @@ Checker.prototype = {
     this._request = null;
   },
 
   /**
    * Whether or not we are allowed to do update checking.
    */
   _enabled: true,
   get enabled() {
-    var aus = Cc["@mozilla.org/updates/update-service;1"].
-              getService(Ci.nsIApplicationUpdateService);
-    var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
-                  aus.canUpdate && this._enabled;
-    return enabled;
+    return getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
+           gCanCheckForUpdates && this._enabled;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   stopChecking: function UC_stopChecking(duration) {
     // Always stop the current check
     if (this._request)