Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: chrome/installer/gcapi_mac/gcapi.mm

Issue 10834102: mac: Let gcapi install chrome as the CGSession owner (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/installer/gcapi_mac/gcapi.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/installer/gcapi_mac/gcapi.h" 5 #include "chrome/installer/gcapi_mac/gcapi.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 #include <grp.h>
9 #include <pwd.h>
8 #include <sys/stat.h> 10 #include <sys/stat.h>
9 #include <sys/types.h> 11 #include <sys/types.h>
10 #include <sys/utsname.h> 12 #include <sys/utsname.h>
11 13
12 namespace { 14 namespace {
13 15
16 // The "~~" prefixes are replaced with the home directory of the
17 // console owner (i.e. not the home directory of the euid).
14 NSString* const kChromeInstallPath = @"/Applications/Google Chrome.app"; 18 NSString* const kChromeInstallPath = @"/Applications/Google Chrome.app";
15 19
16 NSString* const kBrandKey = @"KSBrandID"; 20 NSString* const kBrandKey = @"KSBrandID";
17 NSString* const kSystemBrandPath = @"/Library/Google/Google Chrome Brand.plist"; 21 NSString* const kUserBrandPath = @"~~/Library/Google/Google Chrome Brand.plist";
18 NSString* const kUserBrandPath = @"~/Library/Google/Google Chrome Brand.plist";
19 22
20 NSString* const kSystemKsadminPath = 23 NSString* const kSystemKsadminPath =
21 @"/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/" 24 @"/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/"
22 "Contents/MacOS/ksadmin"; 25 "Contents/MacOS/ksadmin";
23 26
24 NSString* const kUserKsadminPath = 27 NSString* const kUserKsadminPath =
25 @"~/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/" 28 @"~~/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/"
26 "Contents/MacOS/ksadmin"; 29 "Contents/MacOS/ksadmin";
27 30
28 NSString* const kSystemMasterPrefsPath = 31 NSString* const kSystemMasterPrefsPath =
29 @"/Library/Google/Google Chrome Master Preferences"; 32 @"/Library/Google/Google Chrome Master Preferences";
30 NSString* const kUserMasterPrefsPath = 33 NSString* const kUserMasterPrefsPath =
31 @"~/Library/Application Support/Google/Google Chrome Master Preferences"; 34 @"~~/Library/Application Support/Google/Google Chrome Master Preferences";
32 35
33 NSString* const kChannelKey = @"KSChannelID"; 36 NSString* const kChannelKey = @"KSChannelID";
34 NSString* const kVersionKey = @"KSVersion"; 37 NSString* const kVersionKey = @"KSVersion";
35 38
36 // Condensed from chromium's base/mac/mac_util.mm. 39 // Condensed from chromium's base/mac/mac_util.mm.
37 bool IsOSXVersionSupported() { 40 bool IsOSXVersionSupported() {
38 // On 10.6, Gestalt() was observed to be able to spawn threads (see 41 // On 10.6, Gestalt() was observed to be able to spawn threads (see
39 // http://crbug.com/53200). Don't call Gestalt(). 42 // http://crbug.com/53200). Don't call Gestalt().
40 struct utsname uname_info; 43 struct utsname uname_info;
41 if (uname(&uname_info) != 0) 44 if (uname(&uname_info) != 0)
(...skipping 11 matching lines...) Expand all
53 56
54 // The Darwin major version is always 4 greater than the Mac OS X minor 57 // The Darwin major version is always 4 greater than the Mac OS X minor
55 // version for Darwin versions beginning with 6, corresponding to Mac OS X 58 // version for Darwin versions beginning with 6, corresponding to Mac OS X
56 // 10.2. 59 // 10.2.
57 int mac_os_x_minor_version = darwin_major_version - 4; 60 int mac_os_x_minor_version = darwin_major_version - 4;
58 61
59 // Chrome is known to work on 10.6 - 10.8. 62 // Chrome is known to work on 10.6 - 10.8.
60 return mac_os_x_minor_version >= 6 && mac_os_x_minor_version <= 8; 63 return mac_os_x_minor_version >= 6 && mac_os_x_minor_version <= 8;
61 } 64 }
62 65
66 // Returns the pid/gid of the logged-in user, even if getuid() claims that the
67 // current user is root.
68 // Returns NULL on error.
69 passwd* GetRealUserId() {
70 CFDictionaryRef session_info_dict = CGSessionCopyCurrentDictionary();
71 [NSMakeCollectable(session_info_dict) autorelease];
72 if (!session_info_dict)
73 return NULL; // Possibly no screen plugged in.
74
75 CFNumberRef ns_uid = (CFNumberRef)CFDictionaryGetValue(session_info_dict,
76 kCGSessionUserIDKey);
77 if (CFGetTypeID(ns_uid) != CFNumberGetTypeID())
78 return NULL;
79
80 uid_t uid;
81 BOOL success = CFNumberGetValue(ns_uid, kCFNumberSInt32Type, &uid);
82 if (!success)
83 return NULL;
84
85 return getpwuid(uid);
86 }
87
63 enum TicketKind { 88 enum TicketKind {
64 kSystemTicket, kUserTicket 89 kSystemTicket, kUserTicket
65 }; 90 };
66 91
67 BOOL HasChromeTicket(TicketKind kind) { 92 // Replaces "~~" with |home_dir|.
93 NSString* AdjustHomedir(NSString* s, const char* home_dir) {
94 if (![s hasPrefix:@"~~"])
95 return s;
96 NSString* ns_home_dir = [NSString stringWithUTF8String:home_dir];
97 return [ns_home_dir stringByAppendingString:[s substringFromIndex:2]];
98 }
99
100 BOOL HasChromeTicket(TicketKind kind, const passwd* user) {
68 // Don't use Objective-C 2 loop syntax, in case an installer runs on 10.4. 101 // Don't use Objective-C 2 loop syntax, in case an installer runs on 10.4.
69 NSMutableArray* keystonePaths = 102 NSMutableArray* keystone_paths =
70 [NSMutableArray arrayWithObject:kSystemKsadminPath]; 103 [NSMutableArray arrayWithObject:kSystemKsadminPath];
71 if (kind == kUserTicket && geteuid() != 0) 104 if (kind == kUserTicket) {
72 [keystonePaths insertObject:kUserKsadminPath atIndex:0]; 105 [keystone_paths insertObject:AdjustHomedir(kUserKsadminPath, user->pw_dir)
73 NSEnumerator* e = [keystonePaths objectEnumerator]; 106 atIndex:0];
74 id ksPath; 107 }
75 while ((ksPath = [e nextObject])) { 108 NSEnumerator* e = [keystone_paths objectEnumerator];
109 id ks_path;
110 while ((ks_path = [e nextObject])) {
76 NSTask* task = nil; 111 NSTask* task = nil;
77 NSString* string = nil; 112 NSString* string = nil;
78 bool ksadminRanSuccessfully = false; 113 bool ksadmin_ran_successfully = false;
79 114
80 @try { 115 @try {
81 task = [[NSTask alloc] init]; 116 task = [[NSTask alloc] init];
82 [task setLaunchPath:ksPath]; 117 [task setLaunchPath:ks_path];
83 118
84 NSArray* arguments = @[ 119 NSArray* arguments = @[
85 kind == kUserTicket ? @"--user-store" : @"--system-store", 120 kind == kUserTicket ? @"--user-store" : @"--system-store",
86 @"--print-tickets", 121 @"--print-tickets",
87 @"--productid", 122 @"--productid",
88 @"com.google.Chrome", 123 @"com.google.Chrome",
89 ]; 124 ];
125 if (geteuid() == 0 && kind == kUserTicket) {
126 NSString* run_as = [NSString stringWithUTF8String:user->pw_name];
127 [task setLaunchPath:@"/usr/bin/sudo"];
128 arguments = [@[@"-u", run_as, ks_path]
129 arrayByAddingObjectsFromArray:arguments];
130 }
90 [task setArguments:arguments]; 131 [task setArguments:arguments];
91 132
92 NSPipe* pipe = [NSPipe pipe]; 133 NSPipe* pipe = [NSPipe pipe];
93 [task setStandardOutput:pipe]; 134 [task setStandardOutput:pipe];
94 135
95 NSFileHandle* file = [pipe fileHandleForReading]; 136 NSFileHandle* file = [pipe fileHandleForReading];
96 137
97 [task launch]; 138 [task launch];
98 139
99 NSData* data = [file readDataToEndOfFile]; 140 NSData* data = [file readDataToEndOfFile];
100 [task waitUntilExit]; 141 [task waitUntilExit];
101 142
102 ksadminRanSuccessfully = [task terminationStatus] == 0; 143 ksadmin_ran_successfully = [task terminationStatus] == 0;
103 string = [[[NSString alloc] initWithData:data 144 string = [[[NSString alloc] initWithData:data
104 encoding:NSUTF8StringEncoding] autorelease]; 145 encoding:NSUTF8StringEncoding] autorelease];
105 } 146 }
106 @catch (id exception) { 147 @catch (id exception) {
107 // Most likely, ksPath didn't exist. 148 // Most likely, ks_path didn't exist.
108 } 149 }
109 [task release]; 150 [task release];
110 151
111 if (ksadminRanSuccessfully && [string length] > 0) 152 if (ksadmin_ran_successfully && [string length] > 0)
112 return YES; 153 return YES;
113 } 154 }
114 155
115 return NO; 156 return NO;
116 } 157 }
117 158
118 // Returns the file permission mask for files created by gcapi. 159 // File permission mask for files created by gcapi.
119 mode_t Permissions() { 160 const mode_t kUserPermissions = 0755;
120 return 0755; 161 const mode_t kAdminPermissions = 0775;
121 }
122 162
123 BOOL CreatePathToFile(NSString* path) { 163 BOOL CreatePathToFile(NSString* path, const passwd* user) {
124 path = [path stringByDeletingLastPathComponent]; 164 path = [path stringByDeletingLastPathComponent];
125 165
126 // Default owner, group, permissions: 166 // Default owner, group, permissions:
127 // * Permissions are set according to the umask of the current process. For 167 // * Permissions are set according to the umask of the current process. For
128 // more information, see umask. 168 // more information, see umask.
129 // * The owner ID is set to the effective user ID of the process. 169 // * The owner ID is set to the effective user ID of the process.
130 // * The group ID is set to that of the parent directory. 170 // * The group ID is set to that of the parent directory.
131 // The default group ID is fine. Owner ID is fine too, since user directory 171 // The default group ID is fine. Owner ID is fine if creating a system path,
132 // paths won't be created if euid is 0. Do set permissions explicitly; for 172 // but when creating a user path explicitly set the owner in case euid is 0.
133 // admin paths all admins can write, for user paths just the owner may. 173 // Do set permissions explicitly; for admin paths all admins can write, for
134 NSMutableDictionary* attributes = [NSMutableDictionary 174 // user paths just the owner may.
135 dictionaryWithObject:[NSNumber numberWithShort:Permissions()] 175 NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
136 forKey:NSFilePosixPermissions]; 176 if (user) {
137 if (geteuid() == 0) 177 [attributes setObject:[NSNumber numberWithShort:kUserPermissions]
138 [attributes setObject:@"wheel" forKey:NSFileGroupOwnerAccountName]; 178 forKey:NSFilePosixPermissions];
179 [attributes setObject:[NSNumber numberWithInt:user->pw_uid]
180 forKey:NSFileOwnerAccountID];
181 } else {
182 [attributes setObject:[NSNumber numberWithShort:kAdminPermissions]
183 forKey:NSFilePosixPermissions];
184 [attributes setObject:@"admin" forKey:NSFileGroupOwnerAccountName];
185 }
139 186
140 NSFileManager* manager = [NSFileManager defaultManager]; 187 NSFileManager* manager = [NSFileManager defaultManager];
141 return [manager createDirectoryAtPath:path 188 return [manager createDirectoryAtPath:path
142 withIntermediateDirectories:YES 189 withIntermediateDirectories:YES
143 attributes:attributes 190 attributes:attributes
144 error:nil]; 191 error:nil];
145 } 192 }
146 193
147 // Tries to write |data| at |system_path| or if that fails and geteuid() is not 194 // Tries to write |data| at |user_path|.
148 // 0 at |user_path|. Returns the path where it wrote, or nil on failure. 195 // Returns the path where it wrote, or nil on failure.
149 NSString* WriteData(NSData* data, NSString* system_path, NSString* user_path) { 196 NSString* WriteUserData(NSData* data,
197 NSString* user_path,
198 const passwd* user) {
199 user_path = AdjustHomedir(user_path, user->pw_dir);
200 if (CreatePathToFile(user_path, user) &&
201 [data writeToFile:user_path atomically:YES]) {
202 chmod([user_path fileSystemRepresentation], kUserPermissions & ~0111);
203 chown([user_path fileSystemRepresentation], user->pw_uid, user->pw_gid);
204 return user_path;
205 }
206 return nil;
207 }
208
209 // Tries to write |data| at |system_path| or if that fails at |user_path|.
210 // Returns the path where it wrote, or nil on failure.
211 NSString* WriteData(NSData* data,
212 NSString* system_path,
213 NSString* user_path,
214 const passwd* user) {
150 // Try system first. 215 // Try system first.
151 if (CreatePathToFile(system_path) && 216 if (CreatePathToFile(system_path, NULL) &&
152 [data writeToFile:system_path atomically:YES]) { 217 [data writeToFile:system_path atomically:YES]) {
153 // files are created with group of parent dir (good), owner of euid (good). 218 chmod([system_path fileSystemRepresentation], kAdminPermissions & ~0111);
154 chmod([system_path fileSystemRepresentation], Permissions() & ~0111); 219 // Make sure the file is owned by group admin.
220 if (group* group = getgrnam("admin"))
221 chown([system_path fileSystemRepresentation], 0, group->gr_gid);
155 return system_path; 222 return system_path;
156 } 223 }
157 224
158 // Failed, try user. 225 // Failed, try user.
159 // -stringByExpandingTildeInPath returns root's home directory if this is run 226 return WriteUserData(data, user_path, user);
160 // setuid root, and in that case the kSystemBrandPath path above should have
161 // worked anyway. So only try user if geteuid() isn't root.
162 if (geteuid() != 0) {
163 user_path = [user_path stringByExpandingTildeInPath];
164 if (CreatePathToFile(user_path) &&
165 [data writeToFile:user_path atomically:YES]) {
166 chmod([user_path fileSystemRepresentation], Permissions() & ~0111);
167 return user_path;
168 }
169 }
170 return nil;
171 } 227 }
172 228
173 NSString* WriteBrandCode(const char* brand_code) { 229 NSString* WriteBrandCode(const char* brand_code, const passwd* user) {
174 NSDictionary* brand_dict = @{ 230 NSDictionary* brand_dict = @{
175 kBrandKey: [NSString stringWithUTF8String:brand_code], 231 kBrandKey: [NSString stringWithUTF8String:brand_code],
176 }; 232 };
177 NSData* contents = [NSPropertyListSerialization 233 NSData* contents = [NSPropertyListSerialization
178 dataFromPropertyList:brand_dict 234 dataFromPropertyList:brand_dict
179 format:NSPropertyListBinaryFormat_v1_0 235 format:NSPropertyListBinaryFormat_v1_0
180 errorDescription:nil]; 236 errorDescription:nil];
181 237
182 return WriteData(contents, kSystemBrandPath, kUserBrandPath); 238 return WriteUserData(contents, kUserBrandPath, user);
183 } 239 }
184 240
185 BOOL WriteMasterPrefs(const char* master_prefs_contents, 241 BOOL WriteMasterPrefs(const char* master_prefs_contents,
186 size_t master_prefs_contents_size) { 242 size_t master_prefs_contents_size,
243 const passwd* user) {
187 NSData* contents = [NSData dataWithBytes:master_prefs_contents 244 NSData* contents = [NSData dataWithBytes:master_prefs_contents
188 length:master_prefs_contents_size]; 245 length:master_prefs_contents_size];
189 return 246 return WriteData(
190 WriteData(contents, kSystemMasterPrefsPath, kUserMasterPrefsPath) != nil; 247 contents, kSystemMasterPrefsPath, kUserMasterPrefsPath, user) != nil;
191 } 248 }
192 249
193 NSString* PathToFramework(NSString* app_path, NSDictionary* info_plist) { 250 NSString* PathToFramework(NSString* app_path, NSDictionary* info_plist) {
194 NSString* version = [info_plist objectForKey:@"CFBundleShortVersionString"]; 251 NSString* version = [info_plist objectForKey:@"CFBundleShortVersionString"];
195 if (!version) 252 if (!version)
196 return nil; 253 return nil;
197 return [[[app_path 254 return [[[app_path
198 stringByAppendingPathComponent:@"Contents/Versions"] 255 stringByAppendingPathComponent:@"Contents/Versions"]
199 stringByAppendingPathComponent:version] 256 stringByAppendingPathComponent:version]
200 stringByAppendingPathComponent:@"Google Chrome Framework.framework"]; 257 stringByAppendingPathComponent:@"Google Chrome Framework.framework"];
201 } 258 }
202 259
203 NSString* PathToInstallScript(NSString* app_path, NSDictionary* info_plist) { 260 NSString* PathToInstallScript(NSString* app_path, NSDictionary* info_plist) {
204 return [PathToFramework(app_path, info_plist) stringByAppendingPathComponent: 261 return [PathToFramework(app_path, info_plist) stringByAppendingPathComponent:
205 @"Resources/install.sh"]; 262 @"Resources/install.sh"];
206 } 263 }
207 264
208 bool isbrandchar(int c) { 265 bool isbrandchar(int c) {
209 // Always four upper-case alpha chars. 266 // Always four upper-case alpha chars.
210 return c >= 'A' && c <= 'Z'; 267 return c >= 'A' && c <= 'Z';
211 } 268 }
212 269
213 } // namespace 270 } // namespace
214 271
215 int GoogleChromeCompatibilityCheck(unsigned* reasons) { 272 int GoogleChromeCompatibilityCheck(unsigned* reasons) {
216 unsigned local_reasons = 0; 273 unsigned local_reasons = 0;
274 @autoreleasepool {
275 passwd* user = GetRealUserId();
217 276
218 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 277 if (!IsOSXVersionSupported())
278 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED;
219 279
220 if (!IsOSXVersionSupported()) 280 if (HasChromeTicket(kSystemTicket, NULL))
221 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED; 281 local_reasons |= GCCC_ERROR_ALREADYPRESENT;
222 282
223 if (HasChromeTicket(kSystemTicket)) 283 if (HasChromeTicket(kUserTicket, user))
224 local_reasons |= GCCC_ERROR_SYSTEMLEVELALREADYPRESENT; 284 local_reasons |= GCCC_ERROR_ALREADYPRESENT;
225 285
226 if (geteuid() != 0 && HasChromeTicket(kUserTicket)) 286 if (![[NSFileManager defaultManager] isWritableFileAtPath:@"/Applications"])
227 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; 287 local_reasons |= GCCC_ERROR_ACCESSDENIED;
228 288
229 if (![[NSFileManager defaultManager] isWritableFileAtPath:@"/Applications"]) 289 if ([[NSFileManager defaultManager] fileExistsAtPath:kChromeInstallPath])
230 local_reasons |= GCCC_ERROR_ACCESSDENIED; 290 local_reasons |= GCCC_ERROR_ALREADYPRESENT;
231 291 }
232 [pool drain];
233
234 // Done. Copy/return results.
235 if (reasons != NULL) 292 if (reasons != NULL)
236 *reasons = local_reasons; 293 *reasons = local_reasons;
237
238 return local_reasons == 0; 294 return local_reasons == 0;
239 } 295 }
240 296
241 int InstallGoogleChrome(const char* source_path, 297 int InstallGoogleChrome(const char* source_path,
242 const char* brand_code, 298 const char* brand_code,
243 const char* master_prefs_contents, 299 const char* master_prefs_contents,
244 unsigned master_prefs_contents_size) { 300 unsigned master_prefs_contents_size) {
245 if (!GoogleChromeCompatibilityCheck(NULL)) 301 if (!GoogleChromeCompatibilityCheck(NULL))
246 return 0; 302 return 0;
247 303
248 @autoreleasepool { 304 @autoreleasepool {
305 passwd* user = GetRealUserId();
306
249 NSString* app_path = [NSString stringWithUTF8String:source_path]; 307 NSString* app_path = [NSString stringWithUTF8String:source_path];
250 NSString* info_plist_path = 308 NSString* info_plist_path =
251 [app_path stringByAppendingPathComponent:@"Contents/Info.plist"]; 309 [app_path stringByAppendingPathComponent:@"Contents/Info.plist"];
252 NSDictionary* info_plist = 310 NSDictionary* info_plist =
253 [NSDictionary dictionaryWithContentsOfFile:info_plist_path]; 311 [NSDictionary dictionaryWithContentsOfFile:info_plist_path];
254 312
255 // Use install.sh from the Chrome app bundle to copy Chrome to its 313 // Use install.sh from the Chrome app bundle to copy Chrome to its
256 // destination. 314 // destination.
257 NSString* install_script = PathToInstallScript(app_path, info_plist); 315 NSString* install_script = PathToInstallScript(app_path, info_plist);
258 if (!install_script) { 316 if (!install_script) {
259 return 0; 317 return 0;
260 } 318 }
261 319
262 @try { 320 @try {
321 // install.sh tries to make the installed app admin-writable, but
322 // only when it's not run as root.
323 NSString* run_as = [NSString stringWithUTF8String:user->pw_name];
263 NSTask* task = [[[NSTask alloc] init] autorelease]; 324 NSTask* task = [[[NSTask alloc] init] autorelease];
264 [task setLaunchPath:install_script]; 325 [task setLaunchPath:@"/usr/bin/sudo"];
265 [task setArguments:@[app_path, kChromeInstallPath]]; 326 [task setArguments:
327 @[@"-u", run_as, install_script, app_path, kChromeInstallPath]];
266 [task launch]; 328 [task launch];
267 [task waitUntilExit]; 329 [task waitUntilExit];
268 if ([task terminationStatus] != 0) { 330 if ([task terminationStatus] != 0) {
269 return 0; 331 return 0;
270 } 332 }
271 } 333 }
272 @catch (id exception) { 334 @catch (id exception) {
273 return 0; 335 return 0;
274 } 336 }
275 337
276 // Set brand code. If Chrome's Info.plist contains a brand code, use that. 338 // Set brand code. If Chrome's Info.plist contains a brand code, use that.
277 NSString* info_plist_brand = [info_plist objectForKey:kBrandKey]; 339 NSString* info_plist_brand = [info_plist objectForKey:kBrandKey];
278 if (info_plist_brand && 340 if (info_plist_brand &&
279 [info_plist_brand respondsToSelector:@selector(UTF8String)]) 341 [info_plist_brand respondsToSelector:@selector(UTF8String)])
280 brand_code = [info_plist_brand UTF8String]; 342 brand_code = [info_plist_brand UTF8String];
281 343
282 BOOL valid_brand_code = brand_code && strlen(brand_code) == 4 && 344 BOOL valid_brand_code = brand_code && strlen(brand_code) == 4 &&
283 isbrandchar(brand_code[0]) && isbrandchar(brand_code[1]) && 345 isbrandchar(brand_code[0]) && isbrandchar(brand_code[1]) &&
284 isbrandchar(brand_code[2]) && isbrandchar(brand_code[3]); 346 isbrandchar(brand_code[2]) && isbrandchar(brand_code[3]);
285 347
286 NSString* brand_path = nil; 348 NSString* brand_path = nil;
287 if (valid_brand_code) 349 if (valid_brand_code)
288 brand_path = WriteBrandCode(brand_code); 350 brand_path = WriteBrandCode(brand_code, user);
289 351
290 // Write master prefs. 352 // Write master prefs.
291 if (master_prefs_contents) 353 if (master_prefs_contents)
292 WriteMasterPrefs(master_prefs_contents, master_prefs_contents_size); 354 WriteMasterPrefs(master_prefs_contents, master_prefs_contents_size, user);
293 355
294 // TODO Set default browser if requested. Will be tricky when running as 356 // TODO Set default browser if requested.
295 // root.
296 } 357 }
297 return 1; 358 return 1;
298 } 359 }
299 360
300 int LaunchGoogleChrome() { 361 int LaunchGoogleChrome() {
301 @autoreleasepool { 362 @autoreleasepool {
363 // NSWorkspace launches processes as the current console owner,
364 // even when running with euid of 0.
302 return [[NSWorkspace sharedWorkspace] launchApplication:kChromeInstallPath]; 365 return [[NSWorkspace sharedWorkspace] launchApplication:kChromeInstallPath];
303 } 366 }
304 } 367 }
OLDNEW
« no previous file with comments | « chrome/installer/gcapi_mac/gcapi.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698