Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / host / installer / mac / uninstaller / remoting_uninstaller.mm
blob7734d23d75edd215d06e4d1649e06fe771a7e123
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
3 // found in the LICENSE file.
5 #include "remoting/host/installer/mac/uninstaller/remoting_uninstaller.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/mac/scoped_authorizationref.h"
10 #include "remoting/host/constants_mac.h"
13 void logOutput(FILE* pipe) {
14   char readBuffer[128];
15   for (;;) {
16     long bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer) - 1);
17     if (bytesRead < 1)
18       break;
19     readBuffer[bytesRead] = '\0';
20     NSLog(@"%s", readBuffer);
21   }
24 NSArray* convertToNSArray(const char** array) {
25   NSMutableArray* ns_array = [[[NSMutableArray alloc] init] autorelease];
26   int i = 0;
27   const char* element = array[i++];
28   while (element != nullptr) {
29     [ns_array addObject:[NSString stringWithUTF8String:element]];
30     element = array[i++];
31   }
32   return ns_array;
35 @implementation RemotingUninstaller
37 // Keystone
38 const char kKeystoneAdmin[] = "/Library/Google/GoogleSoftwareUpdate/"
39                               "GoogleSoftwareUpdate.bundle/Contents/MacOS/"
40                               "ksadmin";
41 const char kKeystonePID[] = "com.google.chrome_remote_desktop";
43 - (void)runCommand:(const char*)cmd
44      withArguments:(const char**)args {
45   NSTask* task;
46   NSPipe* output = [NSPipe pipe];
47   NSString* result;
49   NSArray* arg_array = convertToNSArray(args);
50   NSLog(@"Executing: %s %@", cmd, [arg_array componentsJoinedByString:@" "]);
52   @try {
53     task = [[[NSTask alloc] init] autorelease];
54     [task setLaunchPath:[NSString stringWithUTF8String:cmd]];
55     [task setArguments:arg_array];
56     [task setStandardInput:[NSPipe pipe]];
57     [task setStandardOutput:output];
58     [task launch];
60     NSData* data = [[output fileHandleForReading] readDataToEndOfFile];
62     [task waitUntilExit];
64     if ([task terminationStatus] != 0) {
65       // TODO(garykac): When we switch to sdk_10.6, show the
66       // [task terminationReason] as well.
67       NSLog(@"Command terminated status=%d", [task terminationStatus]);
68     }
70     result = [[[NSString alloc] initWithData:data
71                                     encoding:NSUTF8StringEncoding]
72               autorelease];
73     if ([result length] != 0) {
74       NSLog(@"Result: %@", result);
75     }
76   }
77   @catch (NSException* exception) {
78     NSLog(@"Exception %@ %@", [exception name], [exception reason]);
79   }
82 - (void)sudoCommand:(const char*)cmd
83       withArguments:(const char**)args
84           usingAuth:(AuthorizationRef)authRef  {
85   NSArray* arg_array = convertToNSArray(args);
86   NSLog(@"Executing (as Admin): %s %@", cmd,
87         [arg_array componentsJoinedByString:@" "]);
88   FILE* pipe = nullptr;
89   OSStatus status;
90   status = AuthorizationExecuteWithPrivileges(authRef, cmd,
91                                               kAuthorizationFlagDefaults,
92                                               (char* const*)args,
93                                               &pipe);
95   if (status == errAuthorizationToolExecuteFailure) {
96     NSLog(@"Error errAuthorizationToolExecuteFailure");
97   } else if (status != errAuthorizationSuccess) {
98     NSLog(@"Error while executing %s. Status=%d",
99           cmd, static_cast<int>(status));
100   } else {
101     logOutput(pipe);
102   }
104   if (pipe != nullptr)
105     fclose(pipe);
108 - (void)sudoDelete:(const char*)filename
109          usingAuth:(AuthorizationRef)authRef  {
110   const char* args[] = { "-rf", filename, nullptr };
111   [self sudoCommand:"/bin/rm" withArguments:args usingAuth:authRef];
114 - (void)shutdownService {
115   const char* launchCtl = "/bin/launchctl";
116   const char* argsStop[] = { "stop", remoting::kServiceName, nullptr };
117   [self runCommand:launchCtl withArguments:argsStop];
119   if ([[NSFileManager defaultManager] fileExistsAtPath:
120        [NSString stringWithUTF8String:remoting::kServicePlistPath]]) {
121     const char* argsUnload[] = { "unload", "-w", "-S", "Aqua",
122                                 remoting::kServicePlistPath, nullptr };
123     [self runCommand:launchCtl withArguments:argsUnload];
124   }
127 - (void)keystoneUnregisterUsingAuth:(AuthorizationRef)authRef {
128   const char* args[] = {"--delete", "--productid", kKeystonePID, "-S", nullptr};
129   [self sudoCommand:kKeystoneAdmin withArguments:args usingAuth:authRef];
132 - (void)remotingUninstallUsingAuth:(AuthorizationRef)authRef {
133   // Remove the enabled file before shutting down the service or else it might
134   // restart itself.
135   [self sudoDelete:remoting::kHostEnabledPath usingAuth:authRef];
137   [self shutdownService];
139   [self sudoDelete:remoting::kServicePlistPath usingAuth:authRef];
140   [self sudoDelete:remoting::kHostBinaryPath usingAuth:authRef];
141   [self sudoDelete:remoting::kHostHelperScriptPath usingAuth:authRef];
142   [self sudoDelete:remoting::kHostConfigFilePath usingAuth:authRef];
143   [self sudoDelete:remoting::kPrefPaneFilePath usingAuth:authRef];
144   [self sudoDelete:remoting::kLogFilePath usingAuth:authRef];
145   [self sudoDelete:remoting::kLogFileConfigPath usingAuth:authRef];
146   [self sudoDelete:remoting::kNativeMessagingManifestPath usingAuth:authRef];
147   [self sudoDelete:remoting::kBrandedUninstallerPath usingAuth:authRef];
148   [self sudoDelete:remoting::kUnbrandedUninstallerPath usingAuth:authRef];
150   [self keystoneUnregisterUsingAuth:authRef];
153 - (OSStatus)remotingUninstall {
154   base::mac::ScopedAuthorizationRef authRef;
155   OSStatus status =
156       AuthorizationCreate(nullptr, kAuthorizationEmptyEnvironment,
157                           kAuthorizationFlagDefaults, authRef.get_pointer());
158   if (status != errAuthorizationSuccess) {
159     [NSException raise:@"AuthorizationCreate Failure"
160                 format:@"Error during AuthorizationCreate status=%d",
161                            static_cast<int>(status)];
162   }
164   AuthorizationItem right = {kAuthorizationRightExecute, 0, nullptr, 0};
165   AuthorizationRights rights = {1, &right};
166   AuthorizationFlags flags = kAuthorizationFlagDefaults |
167                              kAuthorizationFlagInteractionAllowed |
168                              kAuthorizationFlagPreAuthorize |
169                              kAuthorizationFlagExtendRights;
170   status = AuthorizationCopyRights(authRef, &rights, nullptr, flags, nullptr);
171   if (status == errAuthorizationSuccess) {
172     RemotingUninstaller* uninstaller =
173         [[[RemotingUninstaller alloc] init] autorelease];
174     [uninstaller remotingUninstallUsingAuth:authRef];
175   }
176   return status;
179 @end