OLD | NEW |
---|---|
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 <pwd.h> | |
8 #include <sys/stat.h> | 9 #include <sys/stat.h> |
9 #include <sys/types.h> | 10 #include <sys/types.h> |
10 #include <sys/utsname.h> | 11 #include <sys/utsname.h> |
11 | 12 |
12 namespace { | 13 namespace { |
13 | 14 |
15 // The "~~" prefixes are replaced with the home directory of the | |
16 // console owner (i.e. not the home directory of the euid). | |
14 NSString* const kChromeInstallPath = @"/Applications/Google Chrome.app"; | 17 NSString* const kChromeInstallPath = @"/Applications/Google Chrome.app"; |
15 | 18 |
16 NSString* const kBrandKey = @"KSBrandID"; | 19 NSString* const kBrandKey = @"KSBrandID"; |
17 NSString* const kSystemBrandPath = @"/Library/Google/Google Chrome Brand.plist"; | 20 NSString* const kSystemBrandPath = @"/Library/Google/Google Chrome Brand.plist"; |
Mark Mentovai
2012/08/13 13:14:42
Provided we’re just letting Chrome set up a user t
Nico
2012/08/13 14:52:57
Done.
| |
18 NSString* const kUserBrandPath = @"~/Library/Google/Google Chrome Brand.plist"; | 21 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 Loading... | |
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 sessionInfoDict = CGSessionCopyCurrentDictionary(); | |
71 if (!sessionInfoDict) | |
72 return NULL; // Possibly no screen plugged in. | |
73 | |
74 CFNumberRef userUID = (CFNumberRef)CFDictionaryGetValue(sessionInfoDict, | |
Mark Mentovai
2012/08/13 13:14:42
Can you use something like CFCast here?
Nico
2012/08/13 15:42:15
Doneish.
| |
75 kCGSessionUserIDKey); | |
76 uid_t uid; | |
77 BOOL success = CFNumberGetValue(userUID, kCFNumberSInt32Type, &uid); | |
78 CFRelease(sessionInfoDict); | |
79 if (!success) | |
80 return NULL; | |
81 | |
82 return getpwuid(uid); | |
83 } | |
84 | |
63 enum TicketKind { | 85 enum TicketKind { |
64 kSystemTicket, kUserTicket | 86 kSystemTicket, kUserTicket |
65 }; | 87 }; |
66 | 88 |
67 BOOL HasChromeTicket(TicketKind kind) { | 89 // Replaces "~~" with |homedir|. |
90 NSString* AdjustHomedir(NSString* s, const char* homedir) { | |
91 NSString* homeDir = [NSString stringWithUTF8String:homedir]; | |
Mark Mentovai
2012/08/13 13:14:42
Naming nit: home_dir
Nico
2012/08/13 14:52:57
Done.
| |
92 return [s stringByReplacingOccurrencesOfString:@"~~" | |
Mark Mentovai
2012/08/13 13:14:42
I’d be a little more comfortable if this only oper
Nico
2012/08/13 14:52:57
Done.
| |
93 withString:homeDir]; | |
94 } | |
95 | |
96 BOOL HasChromeTicket(TicketKind kind, const char* homedir) { | |
68 // Don't use Objective-C 2 loop syntax, in case an installer runs on 10.4. | 97 // Don't use Objective-C 2 loop syntax, in case an installer runs on 10.4. |
69 NSMutableArray* keystonePaths = | 98 NSMutableArray* keystonePaths = |
Mark Mentovai
2012/08/13 13:14:42
Naming nit: keystone_paths. Line 109 too.
Nico
2012/08/13 14:52:57
Done.
| |
70 [NSMutableArray arrayWithObject:kSystemKsadminPath]; | 99 [NSMutableArray arrayWithObject:kSystemKsadminPath]; |
71 if (kind == kUserTicket && geteuid() != 0) | 100 if (kind == kUserTicket != 0) { |
72 [keystonePaths insertObject:kUserKsadminPath atIndex:0]; | 101 [keystonePaths insertObject:AdjustHomedir(kUserKsadminPath, homedir) |
102 atIndex:0]; | |
103 } | |
73 NSEnumerator* e = [keystonePaths objectEnumerator]; | 104 NSEnumerator* e = [keystonePaths objectEnumerator]; |
74 id ksPath; | 105 id ksPath; |
75 while ((ksPath = [e nextObject])) { | 106 while ((ksPath = [e nextObject])) { |
76 NSTask* task = nil; | 107 NSTask* task = nil; |
77 NSString* string = nil; | 108 NSString* string = nil; |
78 bool ksadminRanSuccessfully = false; | 109 bool ksadminRanSuccessfully = false; |
79 | 110 |
80 @try { | 111 @try { |
112 // XXX does this need to run as other user? or can admin read the user sto re? | |
Mark Mentovai
2012/08/13 13:14:42
What do you mean? That you want to check the conso
Nico
2012/08/13 14:13:33
Right, I imagine this code will usually run with e
Mark Mentovai
2012/08/13 15:04:34
Nico wrote:
Nico
2012/08/13 15:42:16
Done.
| |
113 // it should be able to, so I think this is fine as is? | |
81 task = [[NSTask alloc] init]; | 114 task = [[NSTask alloc] init]; |
82 [task setLaunchPath:ksPath]; | 115 [task setLaunchPath:ksPath]; |
83 | 116 |
84 NSArray* arguments = @[ | 117 NSArray* arguments = @[ |
85 kind == kUserTicket ? @"--user-store" : @"--system-store", | 118 kind == kUserTicket ? @"--user-store" : @"--system-store", |
86 @"--print-tickets", | 119 @"--print-tickets", |
87 @"--productid", | 120 @"--productid", |
88 @"com.google.Chrome", | 121 @"com.google.Chrome", |
89 ]; | 122 ]; |
90 [task setArguments:arguments]; | 123 [task setArguments:arguments]; |
(...skipping 22 matching lines...) Expand all Loading... | |
113 } | 146 } |
114 | 147 |
115 return NO; | 148 return NO; |
116 } | 149 } |
117 | 150 |
118 // Returns the file permission mask for files created by gcapi. | 151 // Returns the file permission mask for files created by gcapi. |
119 mode_t Permissions() { | 152 mode_t Permissions() { |
120 return 0755; | 153 return 0755; |
121 } | 154 } |
122 | 155 |
123 BOOL CreatePathToFile(NSString* path) { | 156 BOOL CreatePathToFile(NSString* path, const passwd* user) { |
124 path = [path stringByDeletingLastPathComponent]; | 157 path = [path stringByDeletingLastPathComponent]; |
125 | 158 |
126 // Default owner, group, permissions: | 159 // Default owner, group, permissions: |
127 // * Permissions are set according to the umask of the current process. For | 160 // * Permissions are set according to the umask of the current process. For |
128 // more information, see umask. | 161 // more information, see umask. |
129 // * The owner ID is set to the effective user ID of the process. | 162 // * 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. | 163 // * 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 | 164 // 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 | 165 // 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. | 166 // Do set permissions explicitly; for admin paths all admins can write, for |
Mark Mentovai
2012/08/13 13:14:42
You haven’t made this so that all admins can write
Nico
2012/08/13 14:52:57
For admins, the group is set to wheel and permissi
Mark Mentovai
2012/08/13 15:04:34
Nico wrote:
Nico
2012/08/13 15:42:16
Done. (?)
| |
167 // user paths just the owner may. | |
134 NSMutableDictionary* attributes = [NSMutableDictionary | 168 NSMutableDictionary* attributes = [NSMutableDictionary |
135 dictionaryWithObject:[NSNumber numberWithShort:Permissions()] | 169 dictionaryWithObject:[NSNumber numberWithShort:Permissions()] |
136 forKey:NSFilePosixPermissions]; | 170 forKey:NSFilePosixPermissions]; |
137 if (geteuid() == 0) | 171 if (user) { |
172 [attributes setObject:[NSNumber numberWithInt:user->pw_uid] | |
173 forKey:NSFileOwnerAccountID]; | |
174 // XXX do this? not needed i think? | |
175 //[attributes setObject:[NSNumber numberWithInt:user->pw_gid] | |
176 //forKey:NSFileGroupOwnerAccountID]; | |
177 } else { | |
138 [attributes setObject:@"wheel" forKey:NSFileGroupOwnerAccountName]; | 178 [attributes setObject:@"wheel" forKey:NSFileGroupOwnerAccountName]; |
179 } | |
139 | 180 |
140 NSFileManager* manager = [NSFileManager defaultManager]; | 181 NSFileManager* manager = [NSFileManager defaultManager]; |
141 return [manager createDirectoryAtPath:path | 182 return [manager createDirectoryAtPath:path |
142 withIntermediateDirectories:YES | 183 withIntermediateDirectories:YES |
143 attributes:attributes | 184 attributes:attributes |
144 error:nil]; | 185 error:nil]; |
145 } | 186 } |
146 | 187 |
147 // Tries to write |data| at |system_path| or if that fails and geteuid() is not | 188 // Tries to write |data| at |system_path| or if that fails at |user_path|. |
148 // 0 at |user_path|. Returns the path where it wrote, or nil on failure. | 189 // Returns the path where it wrote, or nil on failure. |
149 NSString* WriteData(NSData* data, NSString* system_path, NSString* user_path) { | 190 NSString* WriteData(NSData* data, |
191 NSString* system_path, | |
192 NSString* user_path, | |
193 const passwd* user) { | |
194 // XXX do we still want to try to write this to a system path? probably? | |
Mark Mentovai
2012/08/13 13:14:42
Brand file, no. The brand file should only be writ
Nico
2012/08/13 14:52:57
Done.
| |
195 | |
150 // Try system first. | 196 // Try system first. |
151 if (CreatePathToFile(system_path) && | 197 if (CreatePathToFile(system_path, NULL) && |
152 [data writeToFile:system_path atomically:YES]) { | 198 [data writeToFile:system_path atomically:YES]) { |
153 // files are created with group of parent dir (good), owner of euid (good). | 199 // files are created with group of parent dir (good), owner of euid (good). |
154 chmod([system_path fileSystemRepresentation], Permissions() & ~0111); | 200 chmod([system_path fileSystemRepresentation], Permissions() & ~0111); |
155 return system_path; | 201 return system_path; |
156 } | 202 } |
157 | 203 |
158 // Failed, try user. | 204 // Failed, try user. |
159 // -stringByExpandingTildeInPath returns root's home directory if this is run | 205 user_path = AdjustHomedir(user_path, user->pw_dir); |
160 // setuid root, and in that case the kSystemBrandPath path above should have | 206 if (CreatePathToFile(user_path, user) && |
161 // worked anyway. So only try user if geteuid() isn't root. | 207 [data writeToFile:user_path atomically:YES]) { |
162 if (geteuid() != 0) { | 208 chmod([user_path fileSystemRepresentation], Permissions() & ~0111); |
163 user_path = [user_path stringByExpandingTildeInPath]; | 209 chown([user_path fileSystemRepresentation], user->pw_uid, user->pw_gid); |
164 if (CreatePathToFile(user_path) && | 210 return user_path; |
165 [data writeToFile:user_path atomically:YES]) { | |
166 chmod([user_path fileSystemRepresentation], Permissions() & ~0111); | |
167 return user_path; | |
168 } | |
169 } | 211 } |
170 return nil; | 212 return nil; |
171 } | 213 } |
172 | 214 |
173 NSString* WriteBrandCode(const char* brand_code) { | 215 NSString* WriteBrandCode(const char* brand_code, const passwd* user) { |
174 NSDictionary* brand_dict = @{ | 216 NSDictionary* brand_dict = @{ |
175 kBrandKey: [NSString stringWithUTF8String:brand_code], | 217 kBrandKey: [NSString stringWithUTF8String:brand_code], |
176 }; | 218 }; |
177 NSData* contents = [NSPropertyListSerialization | 219 NSData* contents = [NSPropertyListSerialization |
178 dataFromPropertyList:brand_dict | 220 dataFromPropertyList:brand_dict |
179 format:NSPropertyListBinaryFormat_v1_0 | 221 format:NSPropertyListBinaryFormat_v1_0 |
180 errorDescription:nil]; | 222 errorDescription:nil]; |
181 | 223 |
182 return WriteData(contents, kSystemBrandPath, kUserBrandPath); | 224 return WriteData(contents, kSystemBrandPath, kUserBrandPath, user); |
183 } | 225 } |
184 | 226 |
185 BOOL WriteMasterPrefs(const char* master_prefs_contents, | 227 BOOL WriteMasterPrefs(const char* master_prefs_contents, |
186 size_t master_prefs_contents_size) { | 228 size_t master_prefs_contents_size, |
229 const passwd* user) { | |
187 NSData* contents = [NSData dataWithBytes:master_prefs_contents | 230 NSData* contents = [NSData dataWithBytes:master_prefs_contents |
188 length:master_prefs_contents_size]; | 231 length:master_prefs_contents_size]; |
189 return | 232 return WriteData( |
190 WriteData(contents, kSystemMasterPrefsPath, kUserMasterPrefsPath) != nil; | 233 contents, kSystemMasterPrefsPath, kUserMasterPrefsPath, user) != nil; |
191 } | 234 } |
192 | 235 |
193 NSString* PathToFramework(NSString* app_path, NSDictionary* info_plist) { | 236 NSString* PathToFramework(NSString* app_path, NSDictionary* info_plist) { |
194 NSString* version = [info_plist objectForKey:@"CFBundleShortVersionString"]; | 237 NSString* version = [info_plist objectForKey:@"CFBundleShortVersionString"]; |
195 if (!version) | 238 if (!version) |
196 return nil; | 239 return nil; |
197 return [[[app_path | 240 return [[[app_path |
198 stringByAppendingPathComponent:@"Contents/Versions"] | 241 stringByAppendingPathComponent:@"Contents/Versions"] |
199 stringByAppendingPathComponent:version] | 242 stringByAppendingPathComponent:version] |
200 stringByAppendingPathComponent:@"Google Chrome Framework.framework"]; | 243 stringByAppendingPathComponent:@"Google Chrome Framework.framework"]; |
201 } | 244 } |
202 | 245 |
203 NSString* PathToInstallScript(NSString* app_path, NSDictionary* info_plist) { | 246 NSString* PathToInstallScript(NSString* app_path, NSDictionary* info_plist) { |
204 return [PathToFramework(app_path, info_plist) stringByAppendingPathComponent: | 247 return [PathToFramework(app_path, info_plist) stringByAppendingPathComponent: |
205 @"Resources/install.sh"]; | 248 @"Resources/install.sh"]; |
206 } | 249 } |
207 | 250 |
208 bool isbrandchar(int c) { | 251 bool isbrandchar(int c) { |
209 // Always four upper-case alpha chars. | 252 // Always four upper-case alpha chars. |
210 return c >= 'A' && c <= 'Z'; | 253 return c >= 'A' && c <= 'Z'; |
211 } | 254 } |
212 | 255 |
213 } // namespace | 256 } // namespace |
214 | 257 |
215 int GoogleChromeCompatibilityCheck(unsigned* reasons) { | 258 int GoogleChromeCompatibilityCheck(unsigned* reasons) { |
259 passwd* user = GetRealUserId(); | |
260 | |
216 unsigned local_reasons = 0; | 261 unsigned local_reasons = 0; |
217 | 262 |
218 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | 263 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
219 | 264 |
220 if (!IsOSXVersionSupported()) | 265 if (!IsOSXVersionSupported()) |
221 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED; | 266 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED; |
222 | 267 |
223 if (HasChromeTicket(kSystemTicket)) | 268 if (HasChromeTicket(kSystemTicket, user->pw_dir)) |
224 local_reasons |= GCCC_ERROR_SYSTEMLEVELALREADYPRESENT; | 269 local_reasons |= GCCC_ERROR_SYSTEMLEVELALREADYPRESENT; |
225 | 270 |
226 if (geteuid() != 0 && HasChromeTicket(kUserTicket)) | 271 if (HasChromeTicket(kUserTicket, user->pw_dir)) |
227 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; | 272 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; |
228 | 273 |
229 if (![[NSFileManager defaultManager] isWritableFileAtPath:@"/Applications"]) | 274 if (![[NSFileManager defaultManager] isWritableFileAtPath:@"/Applications"]) |
230 local_reasons |= GCCC_ERROR_ACCESSDENIED; | 275 local_reasons |= GCCC_ERROR_ACCESSDENIED; |
231 | 276 |
277 if (!local_reasons && [[NSFileManager defaultManager] | |
278 fileExistsAtPath:@"/Applications/Google Chrome.app"]) { | |
279 local_reasons |= GCCC_ERROR_ACCESSDENIED; | |
Mark Mentovai
2012/08/13 13:14:42
Is this the right “reason” or should you add a new
Nico
2012/08/13 14:52:57
How would the new reason be called?
Or should the
Mark Mentovai
2012/08/13 15:04:34
Nico wrote:
Nico
2012/08/13 15:42:16
Done.
| |
280 } | |
281 | |
232 [pool drain]; | 282 [pool drain]; |
233 | 283 |
234 // Done. Copy/return results. | 284 // Done. Copy/return results. |
235 if (reasons != NULL) | 285 if (reasons != NULL) |
236 *reasons = local_reasons; | 286 *reasons = local_reasons; |
237 | 287 |
238 return local_reasons == 0; | 288 return local_reasons == 0; |
239 } | 289 } |
240 | 290 |
241 int InstallGoogleChrome(const char* source_path, | 291 int InstallGoogleChrome(const char* source_path, |
242 const char* brand_code, | 292 const char* brand_code, |
243 const char* master_prefs_contents, | 293 const char* master_prefs_contents, |
244 unsigned master_prefs_contents_size) { | 294 unsigned master_prefs_contents_size) { |
245 if (!GoogleChromeCompatibilityCheck(NULL)) | 295 if (!GoogleChromeCompatibilityCheck(NULL)) |
246 return 0; | 296 return 0; |
247 | 297 |
298 passwd* user = GetRealUserId(); | |
299 | |
248 @autoreleasepool { | 300 @autoreleasepool { |
249 NSString* app_path = [NSString stringWithUTF8String:source_path]; | 301 NSString* app_path = [NSString stringWithUTF8String:source_path]; |
250 NSString* info_plist_path = | 302 NSString* info_plist_path = |
251 [app_path stringByAppendingPathComponent:@"Contents/Info.plist"]; | 303 [app_path stringByAppendingPathComponent:@"Contents/Info.plist"]; |
252 NSDictionary* info_plist = | 304 NSDictionary* info_plist = |
253 [NSDictionary dictionaryWithContentsOfFile:info_plist_path]; | 305 [NSDictionary dictionaryWithContentsOfFile:info_plist_path]; |
254 | 306 |
255 // Use install.sh from the Chrome app bundle to copy Chrome to its | 307 // Use install.sh from the Chrome app bundle to copy Chrome to its |
256 // destination. | 308 // destination. |
257 NSString* install_script = PathToInstallScript(app_path, info_plist); | 309 NSString* install_script = PathToInstallScript(app_path, info_plist); |
258 if (!install_script) { | 310 if (!install_script) { |
259 return 0; | 311 return 0; |
260 } | 312 } |
261 | 313 |
262 @try { | 314 @try { |
315 // install.sh tries to make the installed app admin-writable, but | |
316 // only when it's not run as root. | |
317 NSString* run_as = [NSString stringWithUTF8String:user->pw_name]; | |
263 NSTask* task = [[[NSTask alloc] init] autorelease]; | 318 NSTask* task = [[[NSTask alloc] init] autorelease]; |
264 [task setLaunchPath:install_script]; | 319 [task setLaunchPath:@"/usr/bin/sudo"]; |
265 [task setArguments:@[app_path, kChromeInstallPath]]; | 320 [task setArguments: |
321 @[@"-u", run_as, install_script, app_path, kChromeInstallPath]]; | |
266 [task launch]; | 322 [task launch]; |
267 [task waitUntilExit]; | 323 [task waitUntilExit]; |
268 if ([task terminationStatus] != 0) { | 324 if ([task terminationStatus] != 0) { |
269 return 0; | 325 return 0; |
270 } | 326 } |
271 } | 327 } |
272 @catch (id exception) { | 328 @catch (id exception) { |
273 return 0; | 329 return 0; |
274 } | 330 } |
275 | 331 |
276 // Set brand code. If Chrome's Info.plist contains a brand code, use that. | 332 // Set brand code. If Chrome's Info.plist contains a brand code, use that. |
277 NSString* info_plist_brand = [info_plist objectForKey:kBrandKey]; | 333 NSString* info_plist_brand = [info_plist objectForKey:kBrandKey]; |
278 if (info_plist_brand && | 334 if (info_plist_brand && |
279 [info_plist_brand respondsToSelector:@selector(UTF8String)]) | 335 [info_plist_brand respondsToSelector:@selector(UTF8String)]) |
280 brand_code = [info_plist_brand UTF8String]; | 336 brand_code = [info_plist_brand UTF8String]; |
281 | 337 |
282 BOOL valid_brand_code = brand_code && strlen(brand_code) == 4 && | 338 BOOL valid_brand_code = brand_code && strlen(brand_code) == 4 && |
283 isbrandchar(brand_code[0]) && isbrandchar(brand_code[1]) && | 339 isbrandchar(brand_code[0]) && isbrandchar(brand_code[1]) && |
284 isbrandchar(brand_code[2]) && isbrandchar(brand_code[3]); | 340 isbrandchar(brand_code[2]) && isbrandchar(brand_code[3]); |
285 | 341 |
286 NSString* brand_path = nil; | 342 NSString* brand_path = nil; |
287 if (valid_brand_code) | 343 if (valid_brand_code) |
288 brand_path = WriteBrandCode(brand_code); | 344 brand_path = WriteBrandCode(brand_code, user); |
289 | 345 |
290 // Write master prefs. | 346 // Write master prefs. |
291 if (master_prefs_contents) | 347 if (master_prefs_contents) |
292 WriteMasterPrefs(master_prefs_contents, master_prefs_contents_size); | 348 WriteMasterPrefs(master_prefs_contents, master_prefs_contents_size, user); |
293 | 349 |
294 // TODO Set default browser if requested. Will be tricky when running as | 350 // TODO Set default browser if requested. |
295 // root. | |
296 } | 351 } |
297 return 1; | 352 return 1; |
298 } | 353 } |
299 | 354 |
300 int LaunchGoogleChrome() { | 355 int LaunchGoogleChrome() { |
356 //passwd* user = GetRealUserId(); | |
357 | |
301 @autoreleasepool { | 358 @autoreleasepool { |
359 // NSWorkspace launches processes as the current console owner, | |
360 // even when running with euid of 0. | |
302 return [[NSWorkspace sharedWorkspace] launchApplication:kChromeInstallPath]; | 361 return [[NSWorkspace sharedWorkspace] launchApplication:kChromeInstallPath]; |
303 } | 362 } |
304 } | 363 } |
OLD | NEW |