diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-25 16:02:36 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-25 16:02:36 +0000 |
commit | 205ccc0ec3dd15f598f890a074af3a7f75937a41 (patch) | |
tree | 93ee4bb6fb24b61593ae3738e899476e0b7c17d4 | |
parent | cfc08c1061b65bd1aac018ecda4290df4a1af0e6 (diff) | |
download | chromium_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.mm | 7 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_main_mac.mm | 57 | ||||
-rw-r--r-- | chrome/browser/mac/keychain_reauthorize.mm | 15 | ||||
-rw-r--r-- | chrome/chrome_installer.gypi | 9 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rwxr-xr-x | chrome/installer/mac/dmgdiffer.sh | 22 | ||||
-rw-r--r-- | chrome/installer/mac/keychain_reauthorize_main.cc | 81 | ||||
-rwxr-xr-x | chrome/installer/mac/keystone_install.sh | 49 | ||||
-rwxr-xr-x | chrome/installer/mac/pkg-dmg | 4 |
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). |