- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / installer / mac / uninstaller / remoting_uninstaller.mm
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.
4
5 #include "remoting/host/installer/mac/uninstaller/remoting_uninstaller.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/mac/scoped_authorizationref.h"
10 #include "remoting/host/constants_mac.h"
11
12
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   }
22 }
23
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 != NULL) {
29     [ns_array addObject:[NSString stringWithUTF8String:element]];
30     element = array[i++];
31   }
32   return ns_array;
33 }
34
35 @implementation RemotingUninstaller
36
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";
42
43 - (void)runCommand:(const char*)cmd
44      withArguments:(const char**)args {
45   NSTask* task;
46   NSPipe* output = [NSPipe pipe];
47   NSString* result;
48
49   NSArray* arg_array = convertToNSArray(args);
50   NSLog(@"Executing: %s %@", cmd, [arg_array componentsJoinedByString:@" "]);
51
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];
59
60     NSData* data = [[output fileHandleForReading] readDataToEndOfFile];
61
62     [task waitUntilExit];
63
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     }
69
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   }
80 }
81
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 = NULL;
89   OSStatus status;
90   status = AuthorizationExecuteWithPrivileges(authRef, cmd,
91                                               kAuthorizationFlagDefaults,
92                                               (char* const*)args,
93                                               &pipe);
94
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   }
103
104   if (pipe != NULL)
105     fclose(pipe);
106 }
107
108 - (void)sudoDelete:(const char*)filename
109          usingAuth:(AuthorizationRef)authRef  {
110   const char* args[] = { "-rf", filename, NULL };
111   [self sudoCommand:"/bin/rm" withArguments:args usingAuth:authRef];
112 }
113
114 - (void)shutdownService {
115   const char* launchCtl = "/bin/launchctl";
116   const char* argsStop[] = { "stop", remoting::kServiceName, NULL };
117   [self runCommand:launchCtl withArguments:argsStop];
118
119   if ([[NSFileManager defaultManager] fileExistsAtPath:
120        [NSString stringWithUTF8String:remoting::kServicePlistPath]]) {
121     const char* argsUnload[] = { "unload", "-w", "-S", "Aqua",
122                                 remoting::kServicePlistPath, NULL };
123     [self runCommand:launchCtl withArguments:argsUnload];
124   }
125 }
126
127 - (void)keystoneUnregisterUsingAuth:(AuthorizationRef)authRef {
128   const char* args[] = { "--delete", "--productid", kKeystonePID, "-S", NULL };
129   [self sudoCommand:kKeystoneAdmin withArguments:args usingAuth:authRef];
130 }
131
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];
136
137   [self shutdownService];
138
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];
149
150   [self keystoneUnregisterUsingAuth:authRef];
151 }
152
153 - (OSStatus)remotingUninstall {
154   base::mac::ScopedAuthorizationRef authRef;
155   OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
156                                         kAuthorizationFlagDefaults, &authRef);
157   if (status != errAuthorizationSuccess) {
158     [NSException raise:@"AuthorizationCreate Failure"
159                 format:@"Error during AuthorizationCreate status=%d",
160                            static_cast<int>(status)];
161   }
162
163   AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
164   AuthorizationRights rights = {1, &right};
165   AuthorizationFlags flags = kAuthorizationFlagDefaults |
166                              kAuthorizationFlagInteractionAllowed |
167                              kAuthorizationFlagPreAuthorize |
168                              kAuthorizationFlagExtendRights;
169   status = AuthorizationCopyRights(authRef, &rights, NULL, flags, NULL);
170   if (status == errAuthorizationSuccess) {
171     RemotingUninstaller* uninstaller =
172         [[[RemotingUninstaller alloc] init] autorelease];
173     [uninstaller remotingUninstallUsingAuth:authRef];
174   }
175   return status;
176 }
177
178 @end