diff options
author | thomasvl@chromium.org <thomasvl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-27 12:53:12 +0000 |
---|---|---|
committer | thomasvl@chromium.org <thomasvl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-27 12:53:12 +0000 |
commit | fc854db57337e41cd7b18cf5965b5a9b111d4416 (patch) | |
tree | f3ef2121ee34e7b4a423359ef26aaa3e6032d412 /chrome/browser | |
parent | 27d81c2f3f2aeec7f418fdd4341f4f9bd82292e8 (diff) | |
download | chromium_src-fc854db57337e41cd7b18cf5965b5a9b111d4416.zip chromium_src-fc854db57337e41cd7b18cf5965b5a9b111d4416.tar.gz chromium_src-fc854db57337e41cd7b18cf5965b5a9b111d4416.tar.bz2 |
[Mac] Brand code support on the Mac:
- During keystone registration pull in the brand file at user to system level.
- Clean up old user level brand files after moving to a system ticket.
- During keystone ticket promotion, use the pref flight script to copy the brand information out to the system level.
- When updating check to see if the user had manually updated the app and gotten a new brand code, if so, migrate that code into the right location.
BUG=39131
TEST=email from tvl to QA with details.
Review URL: http://codereview.chromium.org/1687012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45687 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/keystone_glue.h | 11 | ||||
-rw-r--r-- | chrome/browser/cocoa/keystone_glue.mm | 157 | ||||
-rwxr-xr-x | chrome/browser/cocoa/keystone_promote_preflight.sh | 42 |
3 files changed, 202 insertions, 8 deletions
diff --git a/chrome/browser/cocoa/keystone_glue.h b/chrome/browser/cocoa/keystone_glue.h index 81d74a3..6ae4c1f 100644 --- a/chrome/browser/cocoa/keystone_glue.h +++ b/chrome/browser/cocoa/keystone_glue.h @@ -43,6 +43,16 @@ extern const NSString* const kAutoupdateStatusNotification; extern const NSString* const kAutoupdateStatusStatus; extern const NSString* const kAutoupdateStatusVersion; +namespace { + enum BrandFileType { + kBrandFileTypeNotDetermined = 0, + kBrandFileTypeNone, + kBrandFileTypeUser, + kBrandFileTypeSystem, + }; + +} // namespace + // KeystoneGlue is an adapter around the KSRegistration class, allowing it to // be used without linking directly against its containing KeystoneRegistration // framework. This is used in an environment where most builds (such as @@ -66,6 +76,7 @@ extern const NSString* const kAutoupdateStatusVersion; NSString* url_; NSString* version_; NSString* channel_; // Logically: Dev, Beta, or Stable. + BrandFileType brandFileType_; // And the Keystone registration itself, with the active timer KSRegistration* registration_; // strong diff --git a/chrome/browser/cocoa/keystone_glue.mm b/chrome/browser/cocoa/keystone_glue.mm index 468eca90..5cb125a 100644 --- a/chrome/browser/cocoa/keystone_glue.mm +++ b/chrome/browser/cocoa/keystone_glue.mm @@ -40,6 +40,8 @@ NSString* KSRegistrationPreserveTrustedTesterTokenKey = @"PreserveTTT"; NSString* KSRegistrationTagKey = @"Tag"; NSString* KSRegistrationTagPathKey = @"TagPath"; NSString* KSRegistrationTagKeyKey = @"TagKey"; +NSString* KSRegistrationBrandPathKey = @"BrandPath"; +NSString* KSRegistrationBrandKeyKey = @"BrandKey"; NSString *KSRegistrationDidCompleteNotification = @"KSRegistrationDidCompleteNotification"; @@ -59,6 +61,30 @@ NSString *KSUpdateCheckSuccessfullyInstalledKey = @"SuccessfullyInstalled"; NSString *KSRegistrationRemoveExistingTag = @""; #define KSRegistrationPreserveExistingTag nil +// Constants for the brand file (uses an external file so it can survive updates +// to Chrome. + +#if defined(GOOGLE_CHROME_BUILD) +#define kBrandFileName @"Google Chrome Brand.plist"; +#elif defined(CHROMIUM_BUILD) +#define kBrandFileName @"Chromium Brand.plist"; +#else +#error Unknown branding +#endif + +// These directories are hardcoded in Keystone promotion preflight and the +// Keystone install script, so NSSearchPathForDirectoriesInDomains isn't used +// since the scripts couldn't use anything like that. +NSString* kBrandUserFile = @"~/Library/Google/" kBrandFileName; +NSString* kBrandSystemFile = @"/Library/Google/" kBrandFileName; + +NSString* UserBrandFilePath() { + return [kBrandUserFile stringByStandardizingPath]; +} +NSString* SystemBrandFilePath() { + return [kBrandSystemFile stringByStandardizingPath]; +} + } // namespace @interface KSRegistration : NSObject @@ -144,6 +170,9 @@ NSString *KSRegistrationRemoveExistingTag = @""; - (void)changePermissionsForPromotionWithTool:(NSString*)toolPath; - (void)changePermissionsForPromotionComplete; +// Returns the brand file path to use for Keystone. +- (NSString*)brandFilePath; + @end // @interface KeystoneGlue(Private) const NSString* const kAutoupdateStatusNotification = @@ -154,6 +183,7 @@ const NSString* const kAutoupdateStatusVersion = @"version"; namespace { const NSString* const kChannelKey = @"KSChannelID"; +const NSString* const kBrandKey = @"KSBrandID"; } // namespace @@ -258,6 +288,88 @@ const NSString* const kChannelKey = @"KSChannelID"; channel_ = [channel retain]; } +- (NSString*)brandFilePath { + DCHECK(version_ != nil) << "-loadParameters must be called first"; + + if (brandFileType_ == kBrandFileTypeNotDetermined) { + + // Default to none. + brandFileType_ = kBrandFileTypeNone; + + // Having a channel means Dev/Beta, so there is no brand code to go with + // those. + if ([channel_ length] == 0) { + + NSString* userBrandFile = UserBrandFilePath(); + NSString* systemBrandFile = SystemBrandFilePath(); + + NSFileManager* fm = [NSFileManager defaultManager]; + + // If there is a system brand file, use it. + if ([fm fileExistsAtPath:systemBrandFile]) { + // System + + // Use the system file that is there. + brandFileType_ = kBrandFileTypeSystem; + + // Clean up any old user level file. + if ([fm fileExistsAtPath:userBrandFile]) { + [fm removeItemAtPath:userBrandFile error:NULL]; + } + + } else { + // User + + NSDictionary* infoDictionary = [self infoDictionary]; + NSString* appBundleBrandID = [infoDictionary objectForKey:kBrandKey]; + + NSString* storedBrandID = nil; + if ([fm fileExistsAtPath:userBrandFile]) { + NSDictionary* storedBrandDict = + [NSDictionary dictionaryWithContentsOfFile:userBrandFile]; + storedBrandID = [storedBrandDict objectForKey:kBrandKey]; + } + + if ((appBundleBrandID != nil) && + (![storedBrandID isEqualTo:appBundleBrandID])) { + // App and store don't match, update store and use it. + NSDictionary* storedBrandDict = + [NSDictionary dictionaryWithObject:appBundleBrandID + forKey:kBrandKey]; + if ([storedBrandDict writeToFile:userBrandFile atomically:YES]) { + brandFileType_ = kBrandFileTypeUser; + } + } else if (storedBrandID) { + // Had stored brand, use it. + brandFileType_ = kBrandFileTypeUser; + } + } + } + + } + + NSString* result = nil; + switch (brandFileType_) { + case kBrandFileTypeUser: + result = UserBrandFilePath(); + break; + + case kBrandFileTypeSystem: + result = SystemBrandFilePath(); + break; + + case kBrandFileTypeNotDetermined: + NOTIMPLEMENTED(); + // Fall through + case kBrandFileTypeNone: + // Clear the value. + result = @""; + break; + + } + return result; +} + - (BOOL)loadKeystoneRegistration { if (!productID_ || !appPath_ || !url_ || !version_) return NO; @@ -292,6 +404,15 @@ const NSString* const kChannelKey = @"KSChannelID"; NSNumber* preserveTTToken = [NSNumber numberWithBool:YES]; NSString* tagPath = [self appInfoPlistPath]; + NSString* brandKey = kBrandKey; + NSString* brandPath = [self brandFilePath]; + + if ([brandPath length] == 0) { + // Brand path and brand key must be cleared together or ksadmin seems + // to throw an error. + brandKey = @""; + } + return [NSDictionary dictionaryWithObjectsAndKeys: version_, KSRegistrationVersionKey, xcType, KSRegistrationExistenceCheckerTypeKey, @@ -301,6 +422,8 @@ const NSString* const kChannelKey = @"KSChannelID"; channel_, KSRegistrationTagKey, tagPath, KSRegistrationTagPathKey, kChannelKey, KSRegistrationTagKeyKey, + brandPath, KSRegistrationBrandPathKey, + brandKey, KSRegistrationBrandKeyKey, nil]; } @@ -632,11 +755,15 @@ const NSString* const kChannelKey = @"KSChannelID"; // TODO(mark): Remove when able! // - // keystone_promote_preflight is hopefully temporary. It's here to ensure - // that the Keystone system ticket store is in a usable state for all users - // on the system. Ideally, Keystone's installer or another part of Keystone - // would handle this. The underlying problem is http://b/2285921, and it - // causes http://b/2289908, which this workaround addresses. + // keystone_promote_preflight will copy the current brand information out to + // the system level so all users can share the data as part of the ticket + // promotion. + // + // It will also ensure that the Keystone system ticket store is in a usable + // state for all users on the system. Ideally, Keystone's installer or + // another part of Keystone would handle this. The underlying problem is + // http://b/2285921, and it causes http://b/2289908, which this workaround + // addresses. // // This is run synchronously, which isn't optimal, but // -[KSRegistration promoteWithParameters:authorization:] is currently @@ -650,7 +777,14 @@ const NSString* const kChannelKey = @"KSChannelID"; [mac_util::MainAppBundle() pathForResource:@"keystone_promote_preflight" ofType:@"sh"]; const char* preflightPathC = [preflightPath fileSystemRepresentation]; - const char* arguments[] = {NULL}; + const char* userBrandFile = NULL; + const char* systemBrandFile = NULL; + if (brandFileType_ == kBrandFileTypeUser) { + // Running with user level brand file, promote to the system level. + userBrandFile = [UserBrandFilePath() fileSystemRepresentation]; + systemBrandFile = [SystemBrandFilePath() fileSystemRepresentation]; + } + const char* arguments[] = {userBrandFile, systemBrandFile, NULL}; int exit_status; status = authorization_util::ExecuteWithPrivilegesAndWait( @@ -678,6 +812,17 @@ const NSString* const kChannelKey = @"KSChannelID"; authorization_.swap(authorization); NSDictionary* parameters = [self keystoneParameters]; + + // If the brand file is user level, update parameters to point to the new + // system level file during promotion. + if (brandFileType_ == kBrandFileTypeUser) { + NSMutableDictionary* temp_parameters = + [[parameters mutableCopy] autorelease]; + [temp_parameters setObject:SystemBrandFilePath() + forKey:KSRegistrationBrandPathKey]; + parameters = temp_parameters; + } + if (![registration_ promoteWithParameters:parameters authorization:authorization_]) { [self updateStatus:kAutoupdatePromoteFailed version:nil]; diff --git a/chrome/browser/cocoa/keystone_promote_preflight.sh b/chrome/browser/cocoa/keystone_promote_preflight.sh index d1c4c59..4bf31e8 100755 --- a/chrome/browser/cocoa/keystone_promote_preflight.sh +++ b/chrome/browser/cocoa/keystone_promote_preflight.sh @@ -8,6 +8,10 @@ # environment for Keystone installation. Ultimately, these features should be # integrated directly into the Keystone installation. # +# If the two branding paths are given, then the branding information is also +# copied and the permissions on the system branding file are set to be owned by +# root, but readable by anyone. +# # Note that this script will be invoked with the real user ID set to the # user's ID, but the effective user ID set to 0 (root). bash -p is used on # the first line to prevent bash from setting the effective user ID to the @@ -25,11 +29,45 @@ export PATH="/usr/bin:/usr/sbin:/bin:/sbin" # chrome/browser/cocoa/authorization_util.h. echo "${$}" -if [ ${#} -ne 0 ] ; then - echo "usage: ${0}" >& 2 +if [ ${#} -ne 0 ] && [ ${#} -ne 2 ] ; then + echo "usage: ${0} [USER_BRAND SYSTEM_BRAND]" >& 2 exit 2 fi +if [ ${#} -eq 2 ] ; then + USER_BRAND="${1}" + SYSTEM_BRAND="${2}" + + # Make sure that USER_BRAND is an absolute path and that it exists. + if [ -z "${USER_BRAND}" ] || \ + [ "${USER_BRAND:0:1}" != "/" ] || \ + [ ! -f "${USER_BRAND}" ] ; then + echo "${0}: must provide an absolute path naming an existing user file" >& 2 + exit 3 + fi + + # Make sure that SYSTEM_BRAND is an absolute path. + if [ -z "${SYSTEM_BRAND}" ] || [ "${SYSTEM_BRAND:0:1}" != "/" ] ; then + echo "${0}: must provide an absolute path naming a system file" >& 2 + exit 4 + fi + + # Make sure the directory for the system brand file exists. + SYSTEM_BRAND_DIR=$(dirname "${SYSTEM_BRAND}") + if [ ! -e "${SYSTEM_BRAND_DIR}" ] ; then + mkdir -p "${SYSTEM_BRAND_DIR}" + # Permissions on this directory will be fixed up at the end of this script. + fi + + # Copy the brand file + cp "${USER_BRAND}" "${SYSTEM_BRAND}" >& /dev/null + + # Ensure the right ownership and permissions + chown "root:wheel" "${SYSTEM_BRAND}" >& /dev/null + chmod "a+r,u+w,go-w" "${SYSTEM_BRAND}" >& /dev/null + +fi + OWNER_GROUP="root:admin" CHMOD_MODE="a+rX,u+w,go-w" |