Chromium Code Reviews| 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 "remoting/host/installer/mac/uninstaller/remoting_uninstaller.h" | 5 #include "remoting/host/installer/mac/uninstaller/remoting_uninstaller.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include "base/mac/scoped_authorizationref.h" | 9 #include "base/mac/scoped_authorizationref.h" |
| 10 #include "base/mac/scoped_cftyperef.h" | |
| 11 #include "remoting/host/constants_mac.h" | 10 #include "remoting/host/constants_mac.h" |
| 12 | 11 |
| 13 @implementation RemotingUninstallerAppDelegate | 12 @implementation RemotingUninstaller |
| 14 | |
| 15 NSString* const kLaunchAgentsDir = @"/Library/LaunchAgents"; | |
| 16 NSString* const kPrefPaneDir = @"/Library/PreferencePanes"; | |
| 17 NSString* const kHelperToolsDir = @"/Library/PrivilegedHelperTools"; | |
| 18 NSString* const kApplicationDir = @"/Applications"; | |
| 19 | |
| 20 NSString* const kPrefPaneName = @kServiceName ".prefPane"; | |
| 21 NSString* const kUninstallerName = | |
| 22 @"Chrome Remote Desktop Host Uninstaller.app"; | |
| 23 | 13 |
| 24 // Keystone | 14 // Keystone |
| 25 const char kKeystoneAdmin[] = "/Library/Google/GoogleSoftwareUpdate/" | 15 const char kKeystoneAdmin[] = "/Library/Google/GoogleSoftwareUpdate/" |
| 26 "GoogleSoftwareUpdate.bundle/Contents/MacOS/" | 16 "GoogleSoftwareUpdate.bundle/Contents/MacOS/" |
| 27 "ksadmin"; | 17 "ksadmin"; |
| 28 const char kKeystonePID[] = "com.google.chrome_remote_desktop"; | 18 const char kKeystonePID[] = "com.google.chrome_remote_desktop"; |
| 29 | 19 |
| 30 - (void)dealloc { | |
| 31 [super dealloc]; | |
| 32 } | |
| 33 | |
| 34 - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { | |
| 35 } | |
| 36 | |
| 37 - (void)logOutput:(FILE*) pipe { | 20 - (void)logOutput:(FILE*) pipe { |
| 38 char readBuffer[128]; | 21 char readBuffer[128]; |
| 39 for (;;) { | 22 for (;;) { |
| 40 long bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer) - 1); | 23 long bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer) - 1); |
| 41 if (bytesRead < 1) | 24 if (bytesRead < 1) |
| 42 break; | 25 break; |
| 43 readBuffer[bytesRead] = '\0'; | 26 readBuffer[bytesRead] = '\0'; |
| 44 NSLog(@"%s", readBuffer); | 27 NSLog(@"%s", readBuffer); |
| 45 } | 28 } |
| 46 } | 29 } |
| 47 | 30 |
| 48 - (void)messageBox:(const char*)message { | 31 - (NSArray*)convertToNSArray:(const char**)array { |
|
Lambros
2012/07/23 22:06:47
Is it normal ObjC++ style to add these kinds of pr
garykac
2012/07/23 22:41:09
Not sure about style. I moved it out as a plain fu
| |
| 49 base::mac::ScopedCFTypeRef<CFStringRef> message_ref( | 32 NSMutableArray* ns_array = [[[NSMutableArray alloc] init] autorelease]; |
| 50 CFStringCreateWithCString(NULL, message, (int)strlen(message))); | 33 int i = 0; |
| 51 CFOptionFlags result; | 34 const char* element = array[i++]; |
| 52 CFUserNotificationDisplayAlert(0, kCFUserNotificationNoteAlertLevel, | 35 while (element != NULL) { |
| 53 NULL, NULL, NULL, | 36 [ns_array addObject:[NSString stringWithUTF8String:element]]; |
| 54 CFSTR("Chrome Remote Desktop Uninstaller"), | 37 element = array[i++]; |
| 55 message_ref, NULL, NULL, NULL, &result); | 38 } |
| 39 return ns_array; | |
| 56 } | 40 } |
| 57 | 41 |
| 58 -(void)runCommand:(NSString*)cmd | 42 - (void)runCommand:(const char*)cmd |
| 59 withArguments:(NSArray*)args { | 43 withArguments:(const char**)args { |
| 60 NSTask* task; | 44 NSTask* task; |
| 61 NSPipe* output = [NSPipe pipe]; | 45 NSPipe* output = [NSPipe pipe]; |
| 62 NSString* result; | 46 NSString* result; |
| 63 | 47 |
| 64 NSLog(@"Executing: %@ %@", cmd, [args componentsJoinedByString:@" "]); | 48 NSArray* arg_array = [self convertToNSArray:args]; |
| 49 NSLog(@"Executing: %s %@", cmd, [arg_array componentsJoinedByString:@" "]); | |
| 65 | 50 |
| 66 @try { | 51 @try { |
| 67 task = [[[NSTask alloc] init] autorelease]; | 52 task = [[[NSTask alloc] init] autorelease]; |
| 68 [task setLaunchPath:cmd]; | 53 [task setLaunchPath:[NSString stringWithUTF8String:cmd]]; |
| 69 [task setArguments:args]; | 54 [task setArguments:arg_array]; |
| 70 [task setStandardInput:[NSPipe pipe]]; | 55 [task setStandardInput:[NSPipe pipe]]; |
| 71 [task setStandardOutput:output]; | 56 [task setStandardOutput:output]; |
| 72 [task launch]; | 57 [task launch]; |
| 73 | 58 |
| 74 NSData* data = [[output fileHandleForReading] readDataToEndOfFile]; | 59 NSData* data = [[output fileHandleForReading] readDataToEndOfFile]; |
| 75 | 60 |
| 76 [task waitUntilExit]; | 61 [task waitUntilExit]; |
| 77 | 62 |
| 78 if ([task terminationStatus] != 0) { | 63 if ([task terminationStatus] != 0) { |
| 79 // TODO(garykac): When we switch to sdk_10.6, show the | 64 // TODO(garykac): When we switch to sdk_10.6, show the |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 90 } | 75 } |
| 91 @catch (NSException* exception) { | 76 @catch (NSException* exception) { |
| 92 NSLog(@"Exception %@ %@", [exception name], [exception reason]); | 77 NSLog(@"Exception %@ %@", [exception name], [exception reason]); |
| 93 } | 78 } |
| 94 } | 79 } |
| 95 | 80 |
| 96 - (void)sudoCommand:(const char*)cmd | 81 - (void)sudoCommand:(const char*)cmd |
| 97 withArguments:(const char**)args | 82 withArguments:(const char**)args |
| 98 usingAuth:(AuthorizationRef)authRef { | 83 usingAuth:(AuthorizationRef)authRef { |
| 99 | 84 |
| 100 NSMutableArray* arg_array = [[[NSMutableArray alloc] init] autorelease]; | 85 if (authRef == nil) { |
| 101 int i = 0; | 86 // We're running as root, so just run the command directly. |
|
Lambros
2012/07/23 20:42:35
This feels wrong to me - are you absolutely sure y
garykac
2012/07/23 22:41:09
Hmm.. Previous tests made me think this was requir
| |
| 102 const char* arg = args[i++]; | 87 [self runCommand:cmd withArguments:args]; |
| 103 while (arg != NULL) { | 88 return; |
| 104 [arg_array addObject:[NSString stringWithUTF8String:arg]]; | |
| 105 arg = args[i++]; | |
| 106 } | 89 } |
| 90 | |
| 91 NSArray* arg_array = [self convertToNSArray:args]; | |
| 107 NSLog(@"Executing (as Admin): %s %@", cmd, | 92 NSLog(@"Executing (as Admin): %s %@", cmd, |
| 108 [arg_array componentsJoinedByString:@" "]); | 93 [arg_array componentsJoinedByString:@" "]); |
| 109 FILE* pipe = NULL; | 94 FILE* pipe = NULL; |
| 110 OSStatus status; | 95 OSStatus status; |
| 111 status = AuthorizationExecuteWithPrivileges(authRef, cmd, | 96 status = AuthorizationExecuteWithPrivileges(authRef, cmd, |
| 112 kAuthorizationFlagDefaults, | 97 kAuthorizationFlagDefaults, |
| 113 (char* const*)args, | 98 (char* const*)args, |
| 114 &pipe); | 99 &pipe); |
| 115 | 100 |
| 116 if (status == errAuthorizationToolExecuteFailure) { | 101 if (status == errAuthorizationToolExecuteFailure) { |
| 117 NSLog(@"Error errAuthorizationToolExecuteFailure"); | 102 NSLog(@"Error errAuthorizationToolExecuteFailure"); |
| 118 } else if (status != errAuthorizationSuccess) { | 103 } else if (status != errAuthorizationSuccess) { |
| 119 NSLog(@"Error while executing %s. Status=%lx", cmd, status); | 104 NSLog(@"Error while executing %s. Status=%lx", cmd, status); |
| 120 } else { | 105 } else { |
| 121 [self logOutput:pipe]; | 106 [self logOutput:pipe]; |
| 122 } | 107 } |
| 123 | 108 |
| 124 if (pipe != NULL) | 109 if (pipe != NULL) |
| 125 fclose(pipe); | 110 fclose(pipe); |
| 126 } | 111 } |
| 127 | 112 |
| 128 - (void)sudoDelete:(const char*)filename | 113 - (void)sudoDelete:(const char*)filename |
| 129 usingAuth:(AuthorizationRef)authRef { | 114 usingAuth:(AuthorizationRef)authRef { |
| 130 const char* args[] = { "-rf", filename, NULL }; | 115 const char* args[] = { "-rf", filename, NULL }; |
| 131 [self sudoCommand:"/bin/rm" withArguments:args usingAuth:authRef]; | 116 [self sudoCommand:"/bin/rm" withArguments:args usingAuth:authRef]; |
| 132 } | 117 } |
| 133 | 118 |
| 134 -(void)shutdownService { | 119 - (void)shutdownService { |
| 135 NSString* launchCtl = @"/bin/launchctl"; | 120 const char* launchCtl = "/bin/launchctl"; |
| 136 NSArray* argsStop = [NSArray arrayWithObjects:@"stop", | 121 const char* argsStop[] = { "stop", remoting::kServiceName, NULL }; |
| 137 @kServiceName, nil]; | |
| 138 [self runCommand:launchCtl withArguments:argsStop]; | 122 [self runCommand:launchCtl withArguments:argsStop]; |
| 139 | 123 |
| 140 NSString* plist = [NSString stringWithFormat:@"%@/%@.plist", | 124 if ([[NSFileManager defaultManager] fileExistsAtPath: |
| 141 kLaunchAgentsDir, @kServiceName]; | 125 [NSString stringWithUTF8String:remoting::kServicePlistPath]]) { |
| 142 if ([[NSFileManager defaultManager] fileExistsAtPath:plist]) { | 126 const char* argsUnload[] = { "unload", "-w", "-S", "Aqua", |
| 143 NSArray* argsUnload = [NSArray arrayWithObjects:@"unload", | 127 remoting::kServicePlistPath, NULL }; |
| 144 @"-w", @"-S", @"Aqua", plist, nil]; | |
| 145 [self runCommand:launchCtl withArguments:argsUnload]; | 128 [self runCommand:launchCtl withArguments:argsUnload]; |
| 146 } | 129 } |
| 147 } | 130 } |
| 148 | 131 |
| 149 -(void)keystoneUnregisterUsingAuth:(AuthorizationRef)authRef { | 132 - (void)keystoneUnregisterUsingAuth:(AuthorizationRef)authRef { |
| 150 const char* args[] = { "--delete", "--productid", kKeystonePID, "-S", NULL }; | 133 const char* args[] = { "--delete", "--productid", kKeystonePID, "-S", NULL }; |
| 151 [self sudoCommand:kKeystoneAdmin withArguments:args usingAuth:authRef]; | 134 [self sudoCommand:kKeystoneAdmin withArguments:args usingAuth:authRef]; |
| 152 } | 135 } |
| 153 | 136 |
| 154 -(void)remotingUninstallUsingAuth:(AuthorizationRef)authRef { | 137 - (void)remotingUninstallUsingAuth:(AuthorizationRef)authRef { |
| 155 NSString* host_enabled = [NSString stringWithFormat:@"%@/%@.me2me_enabled", | 138 // Remove the enabled file before shutting down the service or else it might |
| 156 kHelperToolsDir, @kServiceName]; | 139 // restart itself. |
| 157 [self sudoDelete:[host_enabled UTF8String] usingAuth:authRef]; | 140 [self sudoDelete:remoting::kHostEnabledPath usingAuth:authRef]; |
| 158 | 141 |
| 159 [self shutdownService]; | 142 [self shutdownService]; |
| 160 | 143 |
| 161 NSString* plist = [NSString stringWithFormat:@"%@/%@.plist", | 144 [self sudoDelete:remoting::kServicePlistPath usingAuth:authRef]; |
| 162 kLaunchAgentsDir, @kServiceName]; | 145 [self sudoDelete:remoting::kHostBinaryPath usingAuth:authRef]; |
| 163 [self sudoDelete:[plist UTF8String] usingAuth:authRef]; | 146 [self sudoDelete:remoting::kHostHelperScriptPath usingAuth:authRef]; |
| 164 | 147 [self sudoDelete:remoting::kHostConfigFilePath usingAuth:authRef]; |
| 165 NSString* host_binary = [NSString stringWithFormat:@"%@/%@.me2me_host.app", | 148 [self sudoDelete:remoting::kPrefPaneFilePath usingAuth:authRef]; |
| 166 kHelperToolsDir, @kServiceName]; | 149 [self sudoDelete:remoting::kBrandedUninstallerPath usingAuth:authRef]; |
| 167 [self sudoDelete:[host_binary UTF8String] usingAuth:authRef]; | 150 [self sudoDelete:remoting::kUnbrandedUninstallerPath usingAuth:authRef]; |
| 168 | |
| 169 NSString* host_script = [NSString stringWithFormat:@"%@/%@.me2me.sh", | |
| 170 kHelperToolsDir, @kServiceName]; | |
| 171 [self sudoDelete:[host_script UTF8String] usingAuth:authRef]; | |
| 172 | |
| 173 NSString* auth = [NSString stringWithFormat:@"%@/%@.json", | |
| 174 kHelperToolsDir, @kServiceName]; | |
| 175 [self sudoDelete:[auth UTF8String] usingAuth:authRef]; | |
| 176 | |
| 177 NSString* prefpane = [NSString stringWithFormat:@"%@/%@", | |
| 178 kPrefPaneDir, kPrefPaneName]; | |
| 179 [self sudoDelete:[prefpane UTF8String] usingAuth:authRef]; | |
| 180 | |
| 181 NSString* uninstaller = [NSString stringWithFormat:@"%@/%@", | |
| 182 kApplicationDir, kUninstallerName]; | |
| 183 [self sudoDelete:[uninstaller UTF8String] usingAuth:authRef]; | |
| 184 | 151 |
| 185 [self keystoneUnregisterUsingAuth:authRef]; | 152 [self keystoneUnregisterUsingAuth:authRef]; |
| 186 } | 153 } |
| 187 | 154 |
| 188 - (IBAction)uninstall:(NSButton*)sender { | |
| 189 base::mac::ScopedAuthorizationRef authRef; | |
| 190 | |
| 191 NSLog(@"Chrome Remote Desktop uninstall starting."); | |
| 192 | |
| 193 @try { | |
| 194 OSStatus status; | |
| 195 status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, | |
| 196 kAuthorizationFlagDefaults, &authRef); | |
| 197 if (status != errAuthorizationSuccess) { | |
| 198 [NSException raise:@"AuthorizationCreate Failure" | |
| 199 format:@"Error during AuthorizationCreate status=%ld", status]; | |
| 200 } | |
| 201 | |
| 202 AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0}; | |
| 203 AuthorizationRights rights = {1, &right}; | |
| 204 AuthorizationFlags flags = kAuthorizationFlagDefaults | | |
| 205 kAuthorizationFlagInteractionAllowed | | |
| 206 kAuthorizationFlagPreAuthorize | | |
| 207 kAuthorizationFlagExtendRights; | |
| 208 status = AuthorizationCopyRights(authRef, &rights, NULL, flags, NULL); | |
| 209 if (status == errAuthorizationCanceled) { | |
| 210 NSLog(@"Chrome Remote Desktop Host uninstall canceled."); | |
| 211 const char* message = "Chrome Remote Desktop Host uninstall canceled."; | |
| 212 [self messageBox:message]; | |
| 213 } else if (status == errAuthorizationSuccess) { | |
| 214 [self remotingUninstallUsingAuth:authRef]; | |
| 215 | |
| 216 NSLog(@"Chrome Remote Desktop Host uninstall complete."); | |
| 217 const char* message = | |
| 218 "Chrome Remote Desktop Host was successfully uninstalled."; | |
| 219 [self messageBox:message]; | |
| 220 } else { | |
| 221 [NSException raise:@"AuthorizationCopyRights Failure" | |
| 222 format:@"Error during AuthorizationCopyRights status=%ld", status]; | |
| 223 } | |
| 224 } | |
| 225 @catch (NSException* exception) { | |
| 226 NSLog(@"Exception %@ %@", [exception name], [exception reason]); | |
| 227 const char* message = | |
| 228 "Error! Unable to uninstall Chrome Remote Desktop Host."; | |
| 229 [self messageBox:message]; | |
| 230 } | |
| 231 | |
| 232 [NSApp terminate:self]; | |
| 233 } | |
| 234 | |
| 235 - (IBAction)cancel:(id)sender { | |
| 236 [NSApp terminate:self]; | |
| 237 } | |
| 238 | |
| 239 - (IBAction)handleMenuClose:(NSMenuItem*)sender { | |
| 240 [NSApp terminate:self]; | |
| 241 } | |
| 242 | |
| 243 @end | 155 @end |
| 244 | |
| 245 int main(int argc, char* argv[]) | |
| 246 { | |
| 247 return NSApplicationMain(argc, (const char**)argv); | |
| 248 } | |
| 249 | |
| OLD | NEW |