summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-25 16:02:36 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-25 16:02:36 +0000
commit205ccc0ec3dd15f598f890a074af3a7f75937a41 (patch)
tree93ee4bb6fb24b61593ae3738e899476e0b7c17d4
parentcfc08c1061b65bd1aac018ecda4290df4a1af0e6 (diff)
downloadchromium_src-205ccc0ec3dd15f598f890a074af3a7f75937a41.zip
chromium_src-205ccc0ec3dd15f598f890a074af3a7f75937a41.tar.gz
chromium_src-205ccc0ec3dd15f598f890a074af3a7f75937a41.tar.bz2
Merge trunk r137501 to the 19.0.1084 branch.
Do Keychain reauthorization at update time. In addition to the at-launch reauthorization, this adds an at-update reauthorization step. It only runs for users not on a system Keystone ticket, because the updater runs as root when on a system ticket, and root can't read individual user's Keychains. The at-update reauthorization is intended to handle the reauthorization for users who rarely restart Chrome and might miss out on the at-launch step during the window where Chrome is signed by the old certificate but has the new reauthorization code in place. The at-update reauthorization step can remain in place even after the certificate switch occurs by shipping an old reauthorization stub binary signed with the old certificate. BUG=108238 TEST=none Review URL: https://chromiumcodereview.appspot.com/10377173 Review URL: https://chromiumcodereview.appspot.com/10441049 git-svn-id: svn://svn.chromium.org/chrome/branches/1084/src@139049 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/breakpad_mac.mm7
-rw-r--r--chrome/browser/chrome_browser_main_mac.mm57
-rw-r--r--chrome/browser/mac/keychain_reauthorize.mm15
-rw-r--r--chrome/chrome_installer.gypi9
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rwxr-xr-xchrome/installer/mac/dmgdiffer.sh22
-rw-r--r--chrome/installer/mac/keychain_reauthorize_main.cc81
-rwxr-xr-xchrome/installer/mac/keystone_install.sh49
-rwxr-xr-xchrome/installer/mac/pkg-dmg4
10 files changed, 233 insertions, 16 deletions
diff --git a/chrome/app/breakpad_mac.mm b/chrome/app/breakpad_mac.mm
index d99f594..948f73a 100644
--- a/chrome/app/breakpad_mac.mm
+++ b/chrome/app/breakpad_mac.mm
@@ -187,6 +187,11 @@ void InitCrashReporter() {
NSString *reporter_location =
[[NSBundle bundleWithPath:reporter_bundle_location] executablePath];
+ if (!inspector_location || !reporter_location) {
+ VLOG_IF(1, is_browser && base::mac::AmIBundled()) << "Breakpad disabled";
+ return;
+ }
+
NSDictionary* info_dictionary = [main_bundle infoDictionary];
NSMutableDictionary *breakpad_config =
[[info_dictionary mutableCopy] autorelease];
@@ -231,7 +236,7 @@ void InitCrashReporter() {
// Initialize Breakpad.
gBreakpadRef = BreakpadCreate(breakpad_config);
if (!gBreakpadRef) {
- LOG(ERROR) << "Breakpad initializaiton failed";
+ LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initializaiton failed";
return;
}
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index ca36168a..228c297c 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -27,6 +27,28 @@
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/resource/resource_bundle.h"
+namespace {
+
+// This preference is used to track whether the KeychainReauthorize operation
+// has occurred at launch. This operation only makes sense while the
+// application continues to be signed by the old certificate.
+NSString* const kKeychainReauthorizeAtLaunchPref =
+ @"KeychainReauthorizeInAppMay2012";
+const int kKeychainReauthorizeAtLaunchMaxTries = 2;
+
+// Some users rarely restart Chrome, so they might never get a chance to run
+// the at-launch KeychainReauthorize. To account for them, there's also an
+// at-update KeychainReauthorize option, which runs from .keystone_install for
+// users on a user Keystone ticket. This operation may make sense for a period
+// of time after the application switches to being signed by the new
+// certificate, as long as the at-update stub executable is still signed by
+// the old one.
+NSString* const kKeychainReauthorizeAtUpdatePref =
+ @"KeychainReauthorizeAtUpdateMay2012";
+const int kKeychainReauthorizeAtUpdateMaxTries = 3;
+
+} // namespace
+
void RecordBreakpadStatusUMA(MetricsService* metrics) {
metrics->RecordBreakpadRegistration(IsCrashReporterEnabled());
metrics->RecordBreakpadHasDebugger(base::debug::BeingDebugged());
@@ -54,6 +76,27 @@ ChromeBrowserMainPartsMac::ChromeBrowserMainPartsMac(
}
void ChromeBrowserMainPartsMac::PreEarlyInitialization() {
+ if (parsed_command_line().HasSwitch(switches::kKeychainReauthorize)) {
+ if (base::mac::AmIBundled()) {
+ LOG(FATAL) << "Inappropriate process type for Keychain reauthorization";
+ }
+
+ // Do Keychain reauthorization at the time of update installation. This
+ // gets three chances to run. If the first or second try doesn't complete
+ // successfully (crashes or is interrupted for any reason), there will be
+ // another chance. Once this step completes successfully, it should never
+ // have to run again.
+ //
+ // This is kicked off by a special stub executable during an automatic
+ // update. See chrome/installer/mac/keychain_reauthorize_main.cc. This is
+ // done during update installation in additon to browser app launch to
+ // help reauthorize Keychain items for users who never restart Chrome.
+ chrome::browser::mac::KeychainReauthorizeIfNeeded(
+ kKeychainReauthorizeAtUpdatePref, kKeychainReauthorizeAtUpdateMaxTries);
+
+ exit(0);
+ }
+
ChromeBrowserMainPartsPosix::PreEarlyInitialization();
if (base::mac::WasLaunchedAsHiddenLoginItem()) {
@@ -135,16 +178,12 @@ void ChromeBrowserMainPartsMac::PreMainMessageLoopStart() {
[[NSUserDefaults standardUserDefaults]
setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
- // Do Keychain reauthorization. This gets two chances to run. If the first
- // try doesn't complete successfully (crashes or is interrupted for any
- // reason), there will be a second chance. Once this step completes
- // successfully, it should never have to run again.
- NSString* const keychain_reauthorize_pref =
- @"KeychainReauthorizeInAppMay2012";
- const int kKeychainReauthorizeMaxTries = 2;
-
+ // Do Keychain reauthorization at browser app launch. This gets two chances
+ // to run. If the first try doesn't complete successfully (crashes or is
+ // interrupted for any reason), there will be a second chance. Once this
+ // step completes successfully, it should never have to run again.
chrome::browser::mac::KeychainReauthorizeIfNeeded(
- keychain_reauthorize_pref, kKeychainReauthorizeMaxTries);
+ kKeychainReauthorizeAtLaunchPref, kKeychainReauthorizeAtLaunchMaxTries);
}
void ChromeBrowserMainPartsMac::DidEndMainMessageLoop() {
diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm
index 5b94889..50faa8a 100644
--- a/chrome/browser/mac/keychain_reauthorize.mm
+++ b/chrome/browser/mac/keychain_reauthorize.mm
@@ -128,7 +128,12 @@ void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) {
if (pref_value < max_tries) {
if (pref_value > 0) {
// Logs the number of previous tries that didn't complete.
- UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeeded", pref_value);
+ if (base::mac::AmIBundled()) {
+ UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeeded", pref_value);
+ } else {
+ UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdate",
+ pref_value);
+ }
}
++pref_value;
@@ -143,7 +148,13 @@ void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) {
[user_defaults synchronize];
// Logs the try number (1, 2) that succeeded.
- UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededSuccess", pref_value);
+ if (base::mac::AmIBundled()) {
+ UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededSuccess",
+ pref_value);
+ } else {
+ UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdateSuccess",
+ pref_value);
+ }
}
}
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index 84ec4a9..4a098f1 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -864,6 +864,7 @@
'target_name': 'installer_packaging',
'type': 'none',
'dependencies': [
+ 'keychain_reauthorize',
'installer/mac/third_party/bsdiff/goobsdiff.gyp:*',
'installer/mac/third_party/xz/xz.gyp:*',
],
@@ -908,6 +909,7 @@
'files': [
'<(PRODUCT_DIR)/goobsdiff',
'<(PRODUCT_DIR)/goobspatch',
+ '<(PRODUCT_DIR)/keychain_reauthorize',
'<(PRODUCT_DIR)/liblzma_decompress.dylib',
'<(PRODUCT_DIR)/xz',
'<(PRODUCT_DIR)/xzdec',
@@ -938,6 +940,13 @@
},
], # copies
}, # target: installer_packaging
+ {
+ 'target_name': 'keychain_reauthorize',
+ 'type': 'executable',
+ 'sources': [
+ 'installer/mac/keychain_reauthorize_main.cc',
+ ],
+ }, # target: keychain_reauthorize
], # targets
}], # OS=="mac"
[ 'branding == "Chrome"', {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index c606fa2..a7e9874 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1328,6 +1328,10 @@ const char kPasswordStore[] = "password-store";
// Enables the tabs expose feature ( http://crbug.com/50307 ).
const char kEnableExposeForTabs[] = "enable-expose-for-tabs";
+// Performs Keychain reauthorization from the command line on behalf of a
+// special Keychain reauthorization stub executable. Used during auto-update.
+const char kKeychainReauthorize[] = "keychain-reauthorize";
+
// A process type (switches::kProcessType) that relaunches the browser. See
// chrome/browser/mac/relauncher.h.
const char kRelauncherProcess[] = "relauncher";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 31259e0..40dcbad 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -372,6 +372,7 @@ extern const char kPasswordStore[];
#if defined(OS_MACOSX)
extern const char kEnableExposeForTabs[];
+extern const char kKeychainReauthorize[];
extern const char kRelauncherProcess[];
extern const char kUseMockKeychain[];
#endif
diff --git a/chrome/installer/mac/dmgdiffer.sh b/chrome/installer/mac/dmgdiffer.sh
index aaf2cb8..e70ed3e 100755
--- a/chrome/installer/mac/dmgdiffer.sh
+++ b/chrome/installer/mac/dmgdiffer.sh
@@ -1,6 +1,6 @@
#!/bin/bash -p
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -142,6 +142,7 @@ make_patch_fs() {
readonly APP_NAME_RE="${product_name}\\.app"
readonly APP_PLIST="Contents/Info"
readonly APP_VERSION_KEY="CFBundleShortVersionString"
+ readonly APP_BUNDLEID_KEY="CFBundleIdentifier"
readonly KS_VERSION_KEY="KSVersion"
readonly KS_PRODUCT_KEY="KSProductID"
readonly KS_CHANNEL_KEY="KSChannelID"
@@ -168,6 +169,13 @@ make_patch_fs() {
fi
local old_app_version_build="${BASH_REMATCH[1]}"
+ local old_app_bundleid
+ if ! old_app_bundleid="$(defaults read "${old_app_plist}" \
+ "${APP_BUNDLEID_KEY}")"; then
+ err "could not read old app bundle ID"
+ exit 10
+ fi
+
local old_ks_plist="${old_app_plist}"
local old_ks_version
if ! old_ks_version="$(defaults read "${old_ks_plist}" \
@@ -235,6 +243,18 @@ make_patch_fs() {
exit 13
fi
+ local patch_keychain_reauthorize_dir="${patch_fs}/.keychain_reauthorize"
+ if ! mkdir "${patch_keychain_reauthorize_dir}"; then
+ err "could not mkdir patch_keychain_reauthorize_dir"
+ exit 13
+ fi
+
+ if ! cp -p "${SCRIPT_DIR}/.keychain_reauthorize/${old_app_bundleid}" \
+ "${patch_keychain_reauthorize_dir}/${old_app_bundleid}"; then
+ err "could not copy keychain_reauthorize"
+ exit 13
+ fi
+
local patch_dotpatch_dir="${patch_fs}/.patch"
if ! mkdir "${patch_dotpatch_dir}"; then
err "could not mkdir patch_dotpatch_dir"
diff --git a/chrome/installer/mac/keychain_reauthorize_main.cc b/chrome/installer/mac/keychain_reauthorize_main.cc
new file mode 100644
index 0000000..9fb7ffc
--- /dev/null
+++ b/chrome/installer/mac/keychain_reauthorize_main.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The entry point for the Mac Chrome Keychain Reauthorization process,
+// which runs at update time. It needs to be signed by the old certificate
+// in order to have access to the existing Keychain items, so it takes the
+// form of this little stub that uses dlopen and dlsym to find a current
+// Chrome framework, which can be signed by any certificate including the new
+// one. This architecture allows the updater to peform keychain
+// reauthorization by using an old copy of this executable signed with the old
+// certificate even after the rest of Chrome has switched to being signed with
+// the new certificate. The reauthorization code remains in the framework to
+// avoid duplication and to allow it to change over time without having to
+// re-sign this executable with the old certificate. This uses dlopen and
+// dlsym to avoid problems linking with a library whose path is not fixed and
+// whose version changes with each release.
+//
+// In order to satisfy the requirements of items stored in the Keychain, this
+// executable needs to be named "com.google.Chrome" or
+// "com.google.Chrome.canary", because the original applications were signed
+// with deignated requirements requiring the identifier to be one of those
+// names.
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+__attribute__((visibility("default")))
+int main(int argc, char* argv[]) {
+ const char* me = argv[0];
+
+ // Since |me| will be something like "com.google.Chrome", also use an
+ // alternate name to avoid confusion.
+ const char alt_me[] = "keychain_reauthorize";
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s (%s) <framework_code_path>\n", me, alt_me);
+ return 1;
+ }
+
+ const char* framework_code_path = argv[1];
+ void* framework_code = dlopen(framework_code_path, RTLD_LAZY | RTLD_GLOBAL);
+ if (!framework_code) {
+ fprintf(stderr, "%s (%s): dlopen: %s\n", me, alt_me, dlerror());
+ return 1;
+ }
+
+ typedef int(*ChromeMainType)(int, char**);
+ ChromeMainType chrome_main =
+ reinterpret_cast<ChromeMainType>(dlsym(framework_code, "ChromeMain"));
+ if (!chrome_main) {
+ fprintf(stderr, "%s (%s): dlsym: %s\n", me, alt_me, dlerror());
+ return 1;
+ }
+
+ // Use strdup to get char* copies of the original const char* strings.
+ // ChromeMain doesn't promise that it won't touch its argv.
+ char* me_copy = strdup(me);
+ char* keychain_reauthorize_argument = strdup("--keychain-reauthorize");
+ char* chrome_main_argv[] = {
+ me_copy,
+ keychain_reauthorize_argument
+ };
+
+ int chrome_main_argc = sizeof(chrome_main_argv) / sizeof(chrome_main_argv[0]);
+
+ // Not expected to return.
+ int rv = chrome_main(chrome_main_argc, chrome_main_argv);
+
+ fprintf(stderr, "%s (%s): NOTREACHED!\n", me, alt_me);
+
+ free(keychain_reauthorize_argument);
+ free(me_copy);
+
+ // As in chrome_exe_main_mac.cc: exit, don't return from main, to avoid the
+ // apparent removal of main from stack backtraces under tail call
+ // optimization.
+ exit(rv);
+}
diff --git a/chrome/installer/mac/keystone_install.sh b/chrome/installer/mac/keystone_install.sh
index 24609d2..b48329e 100755
--- a/chrome/installer/mac/keystone_install.sh
+++ b/chrome/installer/mac/keystone_install.sh
@@ -1,6 +1,6 @@
#!/bin/bash -p
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -413,6 +413,7 @@ main() {
readonly UNROOTED_DEBUG_FILE="Library/Google/Google Chrome Updater Debug"
readonly APP_VERSION_KEY="CFBundleShortVersionString"
+ readonly APP_BUNDLEID_KEY="CFBundleIdentifier"
readonly KS_VERSION_KEY="KSVersion"
readonly KS_PRODUCT_KEY="KSProductID"
readonly KS_URL_KEY="KSUpdateURL"
@@ -420,6 +421,7 @@ main() {
readonly KS_BRAND_KEY="KSBrandID"
readonly QUARANTINE_ATTR="com.apple.quarantine"
+ readonly KEYCHAIN_REAUTHORIZE_DIR=".keychain_reauthorize"
# Don't use rsync -a, because -a expands to -rlptgoD. -g and -o copy owners
# and groups, respectively, from the source, and that is undesirable in this
@@ -1268,6 +1270,51 @@ main() {
2> /dev/null
fi
+ # Do Keychain reauthorization. This involves running a stub executable on
+ # the dmg that loads the newly-updated framework and jumps to it to perform
+ # the reauthorization. The stub executable can be signed by the old
+ # certificate even after the rest of Chrome switches to the new certificate,
+ # so it still has access to the old Keychain items. The stub executable is
+ # an unbundled flat file executable whose name matches the real
+ # application's bundle identifier, so it's permitted access to the Keychain
+ # items. Doing a reauthorization step at update time reauthorizes Keychain
+ # items for users who never bother restarting Chrome, and provides a
+ # mechanism to continue doing reauthorizations even after the certificate
+ # changes. However, it only works for non-system ticket installations of
+ # Chrome, because the updater runs as root when on a system ticket, and root
+ # can't access individual user Keychains.
+ #
+ # Even if the reauthorization tool is launched, it doesn't necessarily try
+ # to do anything. It will only attempt to perform a reauthorization if one
+ # hasn't yet been done at update time.
+ note "maybe reauthorizing Keychain"
+
+ if [[ -z "${system_ticket}" ]]; then
+ local new_bundleid_app
+ new_bundleid_app="$(defaults read "${installed_app_plist}" \
+ "${APP_BUNDLEID_KEY}" || true)"
+ note "new_bundleid_app = ${new_bundleid_app}"
+
+ local keychain_reauthorize_dir="\
+${update_dmg_mount_point}/${KEYCHAIN_REAUTHORIZE_DIR}"
+ local keychain_reauthorize_path="\
+${keychain_reauthorize_dir}/${new_bundleid_app}"
+ note "keychain_reauthorize_path = ${keychain_reauthorize_path}"
+
+ if [[ -x "${keychain_reauthorize_path}" ]]; then
+ local framework_dir="${new_versioned_dir}/${FRAMEWORK_DIR}"
+ local framework_code_path="${framework_dir}/${FRAMEWORK_NAME}"
+ note "framework_code_path = ${framework_code_path}"
+
+ if [[ -f "${framework_code_path}" ]]; then
+ note "reauthorizing Keychain"
+ "${keychain_reauthorize_path}" "${framework_code_path}"
+ fi
+ fi
+ else
+ note "system ticket, not reauthorizing Keychain"
+ fi
+
# Great success!
note "done!"
diff --git a/chrome/installer/mac/pkg-dmg b/chrome/installer/mac/pkg-dmg
index 4030b6d..82b9010 100755
--- a/chrome/installer/mac/pkg-dmg
+++ b/chrome/installer/mac/pkg-dmg
@@ -308,10 +308,10 @@ my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity);
'cmd_hdiutil' => 'hdiutil',
'cmd_mkdir' => 'mkdir',
'cmd_mktemp' => 'mktemp',
- 'cmd_Rez' => '/Developer/Tools/Rez',
+ 'cmd_Rez' => '/usr/bin/Rez',
'cmd_rm' => 'rm',
'cmd_rsync' => 'rsync',
- 'cmd_SetFile' => '/Developer/Tools/SetFile',
+ 'cmd_SetFile' => '/usr/bin/SetFile',
# create_directly indicates whether hdiutil create supports
# -srcfolder and -srcdevice. It does on >= 10.3 (Panther).