| 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 #import "remoting/host/me2me_preference_pane.h" | 5 #import "remoting/host/me2me_preference_pane.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 #include <CommonCrypto/CommonHMAC.h> | 8 #include <CommonCrypto/CommonHMAC.h> |
| 9 #include <errno.h> | 9 #include <errno.h> |
| 10 #include <launch.h> | 10 #include <launch.h> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "third_party/jsoncpp/source/include/json/writer.h" | 26 #include "third_party/jsoncpp/source/include/json/writer.h" |
| 27 #include "third_party/modp_b64/modp_b64.h" | 27 #include "third_party/modp_b64/modp_b64.h" |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 bool GetTemporaryConfigFilePath(std::string* path) { | 31 bool GetTemporaryConfigFilePath(std::string* path) { |
| 32 NSString* filename = NSTemporaryDirectory(); | 32 NSString* filename = NSTemporaryDirectory(); |
| 33 if (filename == nil) | 33 if (filename == nil) |
| 34 return false; | 34 return false; |
| 35 | 35 |
| 36 filename = [filename stringByAppendingString:@"/" kServiceName ".json"]; | 36 *path = [[NSString stringWithFormat:@"%@/%s", |
| 37 *path = [filename UTF8String]; | 37 filename, remoting::kHostConfigFileName] UTF8String]; |
| 38 return true; | 38 return true; |
| 39 } | 39 } |
| 40 | 40 |
| 41 bool IsConfigValid(const remoting::JsonHostConfig* config) { | 41 bool IsConfigValid(const remoting::JsonHostConfig* config) { |
| 42 std::string value; | 42 std::string value; |
| 43 return (config->GetString(remoting::kHostIdConfigPath, &value) && | 43 return (config->GetString(remoting::kHostIdConfigPath, &value) && |
| 44 config->GetString(remoting::kHostSecretHashConfigPath, &value) && | 44 config->GetString(remoting::kHostSecretHashConfigPath, &value) && |
| 45 config->GetString(remoting::kXmppLoginConfigPath, &value)); | 45 config->GetString(remoting::kXmppLoginConfigPath, &value)); |
| 46 } | 46 } |
| 47 | 47 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 *pid = line_pid; | 219 *pid = line_pid; |
| 220 } | 220 } |
| 221 | 221 |
| 222 return status; | 222 return status; |
| 223 } | 223 } |
| 224 | 224 |
| 225 } // namespace mac | 225 } // namespace mac |
| 226 } // namespace base | 226 } // namespace base |
| 227 | 227 |
| 228 namespace remoting { | 228 namespace remoting { |
| 229 |
| 229 JsonHostConfig::JsonHostConfig(const std::string& filename) | 230 JsonHostConfig::JsonHostConfig(const std::string& filename) |
| 230 : filename_(filename) { | 231 : filename_(filename) { |
| 231 } | 232 } |
| 232 | 233 |
| 233 JsonHostConfig::~JsonHostConfig() { | 234 JsonHostConfig::~JsonHostConfig() { |
| 234 } | 235 } |
| 235 | 236 |
| 236 bool JsonHostConfig::Read() { | 237 bool JsonHostConfig::Read() { |
| 237 std::ifstream file(filename_.c_str()); | 238 std::ifstream file(filename_.c_str()); |
| 238 Json::Reader reader; | 239 Json::Reader reader; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 } | 276 } |
| 276 | 277 |
| 277 - (void)willSelect { | 278 - (void)willSelect { |
| 278 have_new_config_ = NO; | 279 have_new_config_ = NO; |
| 279 awaiting_service_stop_ = NO; | 280 awaiting_service_stop_ = NO; |
| 280 | 281 |
| 281 NSDistributedNotificationCenter* center = | 282 NSDistributedNotificationCenter* center = |
| 282 [NSDistributedNotificationCenter defaultCenter]; | 283 [NSDistributedNotificationCenter defaultCenter]; |
| 283 [center addObserver:self | 284 [center addObserver:self |
| 284 selector:@selector(onNewConfigFile:) | 285 selector:@selector(onNewConfigFile:) |
| 285 name:@kServiceName | 286 name:[NSString stringWithUTF8String:remoting::kServiceName] |
| 286 object:nil]; | 287 object:nil]; |
| 287 | 288 |
| 288 service_status_timer_ = | 289 service_status_timer_ = |
| 289 [[NSTimer scheduledTimerWithTimeInterval:2.0 | 290 [[NSTimer scheduledTimerWithTimeInterval:2.0 |
| 290 target:self | 291 target:self |
| 291 selector:@selector(refreshServiceStatus:) | 292 selector:@selector(refreshServiceStatus:) |
| 292 userInfo:nil | 293 userInfo:nil |
| 293 repeats:YES] retain]; | 294 repeats:YES] retain]; |
| 294 [self updateServiceStatus]; | 295 [self updateServiceStatus]; |
| 295 [self updateAuthorizationStatus]; | 296 [self updateAuthorizationStatus]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 307 | 308 |
| 308 - (void)willUnselect { | 309 - (void)willUnselect { |
| 309 NSDistributedNotificationCenter* center = | 310 NSDistributedNotificationCenter* center = |
| 310 [NSDistributedNotificationCenter defaultCenter]; | 311 [NSDistributedNotificationCenter defaultCenter]; |
| 311 [center removeObserver:self]; | 312 [center removeObserver:self]; |
| 312 | 313 |
| 313 [service_status_timer_ invalidate]; | 314 [service_status_timer_ invalidate]; |
| 314 [service_status_timer_ release]; | 315 [service_status_timer_ release]; |
| 315 service_status_timer_ = nil; | 316 service_status_timer_ = nil; |
| 316 | 317 |
| 317 [self notifyPlugin:kUpdateFailedNotificationName]; | 318 [self notifyPlugin:UPDATE_FAILED_NOTIFICATION_NAME]; |
| 318 } | 319 } |
| 319 | 320 |
| 320 - (void)applyConfiguration:(id)sender | 321 - (void)applyConfiguration:(id)sender |
| 321 pin:(NSString*)pin { | 322 pin:(NSString*)pin { |
| 322 if (!have_new_config_) { | 323 if (!have_new_config_) { |
| 323 // It shouldn't be possible to hit the button if there is no config to | 324 // It shouldn't be possible to hit the button if there is no config to |
| 324 // apply, but check anyway just in case it happens somehow. | 325 // apply, but check anyway just in case it happens somehow. |
| 325 return; | 326 return; |
| 326 } | 327 } |
| 327 | 328 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 351 // Ensure the authorization token is up-to-date before using it. | 352 // Ensure the authorization token is up-to-date before using it. |
| 352 [self updateAuthorizationStatus]; | 353 [self updateAuthorizationStatus]; |
| 353 [self updateUI]; | 354 [self updateUI]; |
| 354 if (!is_pane_unlocked_) | 355 if (!is_pane_unlocked_) |
| 355 return; | 356 return; |
| 356 | 357 |
| 357 if (![self runHelperAsRootWithCommand:"--disable" | 358 if (![self runHelperAsRootWithCommand:"--disable" |
| 358 inputData:""]) { | 359 inputData:""]) { |
| 359 NSLog(@"Failed to run the helper tool"); | 360 NSLog(@"Failed to run the helper tool"); |
| 360 [self showError]; | 361 [self showError]; |
| 361 [self notifyPlugin: kUpdateFailedNotificationName]; | 362 [self notifyPlugin:UPDATE_FAILED_NOTIFICATION_NAME]; |
| 362 return; | 363 return; |
| 363 } | 364 } |
| 364 | 365 |
| 365 // Stop the launchd job. This cannot easily be done by the helper tool, | 366 // Stop the launchd job. This cannot easily be done by the helper tool, |
| 366 // since the launchd job runs in the current user's context. | 367 // since the launchd job runs in the current user's context. |
| 367 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; | 368 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; |
| 368 awaiting_service_stop_ = YES; | 369 awaiting_service_stop_ = YES; |
| 369 } | 370 } |
| 370 | 371 |
| 371 - (void)onNewConfigFile:(NSNotification*)notification { | 372 - (void)onNewConfigFile:(NSNotification*)notification { |
| 372 [self checkInstalledVersion]; | 373 [self checkInstalledVersion]; |
| 373 if (!restart_pending_or_canceled_) | 374 if (!restart_pending_or_canceled_) |
| 374 [self readNewConfig]; | 375 [self readNewConfig]; |
| 375 | 376 |
| 376 [self updateUI]; | 377 [self updateUI]; |
| 377 } | 378 } |
| 378 | 379 |
| 379 - (void)refreshServiceStatus:(NSTimer*)timer { | 380 - (void)refreshServiceStatus:(NSTimer*)timer { |
| 380 BOOL was_running = is_service_running_; | 381 BOOL was_running = is_service_running_; |
| 381 [self updateServiceStatus]; | 382 [self updateServiceStatus]; |
| 382 if (awaiting_service_stop_ && !is_service_running_) { | 383 if (awaiting_service_stop_ && !is_service_running_) { |
| 383 awaiting_service_stop_ = NO; | 384 awaiting_service_stop_ = NO; |
| 384 [self notifyPlugin:kUpdateSucceededNotificationName]; | 385 [self notifyPlugin:UPDATE_SUCCEEDED_NOTIFICATION_NAME]; |
| 385 } | 386 } |
| 386 | 387 |
| 387 if (was_running != is_service_running_) | 388 if (was_running != is_service_running_) |
| 388 [self updateUI]; | 389 [self updateUI]; |
| 389 } | 390 } |
| 390 | 391 |
| 391 - (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view { | 392 - (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view { |
| 392 [self updateAuthorizationStatus]; | 393 [self updateAuthorizationStatus]; |
| 393 [self updateUI]; | 394 [self updateUI]; |
| 394 } | 395 } |
| 395 | 396 |
| 396 - (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view { | 397 - (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view { |
| 397 [self updateAuthorizationStatus]; | 398 [self updateAuthorizationStatus]; |
| 398 [self updateUI]; | 399 [self updateUI]; |
| 399 } | 400 } |
| 400 | 401 |
| 401 - (void)updateServiceStatus { | 402 - (void)updateServiceStatus { |
| 402 pid_t job_pid = base::mac::PIDForJob(kServiceName); | 403 pid_t job_pid = base::mac::PIDForJob(remoting::kServiceName); |
| 403 is_service_running_ = (job_pid > 0); | 404 is_service_running_ = (job_pid > 0); |
| 404 } | 405 } |
| 405 | 406 |
| 406 - (void)updateAuthorizationStatus { | 407 - (void)updateAuthorizationStatus { |
| 407 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; | 408 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; |
| 408 } | 409 } |
| 409 | 410 |
| 410 - (void)readNewConfig { | 411 - (void)readNewConfig { |
| 411 std::string file; | 412 std::string file; |
| 412 if (!GetTemporaryConfigFilePath(&file)) { | 413 if (!GetTemporaryConfigFilePath(&file)) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 NSLog(@"Failed to run the helper tool"); | 519 NSLog(@"Failed to run the helper tool"); |
| 519 [self showError]; | 520 [self showError]; |
| 520 return; | 521 return; |
| 521 } | 522 } |
| 522 | 523 |
| 523 have_new_config_ = NO; | 524 have_new_config_ = NO; |
| 524 | 525 |
| 525 // If the service is running, send a signal to cause it to reload its | 526 // If the service is running, send a signal to cause it to reload its |
| 526 // configuration, otherwise start the service. | 527 // configuration, otherwise start the service. |
| 527 if (is_service_running_) { | 528 if (is_service_running_) { |
| 528 pid_t job_pid = base::mac::PIDForJob(kServiceName); | 529 pid_t job_pid = base::mac::PIDForJob(remoting::kServiceName); |
| 529 if (job_pid > 0) { | 530 if (job_pid > 0) { |
| 530 kill(job_pid, SIGHUP); | 531 kill(job_pid, SIGHUP); |
| 531 } else { | 532 } else { |
| 532 NSLog(@"Failed to obtain PID of service " kServiceName); | 533 NSLog(@"Failed to obtain PID of service %s", remoting::kServiceName); |
| 533 [self showError]; | 534 [self showError]; |
| 534 } | 535 } |
| 535 } else { | 536 } else { |
| 536 [self sendJobControlMessage:LAUNCH_KEY_STARTJOB]; | 537 [self sendJobControlMessage:LAUNCH_KEY_STARTJOB]; |
| 537 } | 538 } |
| 538 | 539 |
| 539 // Broadcast a distributed notification to inform the plugin that the | 540 // Broadcast a distributed notification to inform the plugin that the |
| 540 // configuration has been applied. | 541 // configuration has been applied. |
| 541 [self notifyPlugin: kUpdateSucceededNotificationName]; | 542 [self notifyPlugin:UPDATE_SUCCEEDED_NOTIFICATION_NAME]; |
| 542 } | 543 } |
| 543 | 544 |
| 544 - (BOOL)runHelperAsRootWithCommand:(const char*)command | 545 - (BOOL)runHelperAsRootWithCommand:(const char*)command |
| 545 inputData:(const std::string&)input_data { | 546 inputData:(const std::string&)input_data { |
| 546 AuthorizationRef authorization = | 547 AuthorizationRef authorization = |
| 547 [[authorization_view_ authorization] authorizationRef]; | 548 [[authorization_view_ authorization] authorizationRef]; |
| 548 if (!authorization) { | 549 if (!authorization) { |
| 549 NSLog(@"Failed to obtain authorizationRef"); | 550 NSLog(@"Failed to obtain authorizationRef"); |
| 550 return NO; | 551 return NO; |
| 551 } | 552 } |
| 552 | 553 |
| 553 // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges | 554 // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges |
| 554 // call with a launchd-based helper tool, which is more secure. | 555 // call with a launchd-based helper tool, which is more secure. |
| 555 // http://crbug.com/120903 | 556 // http://crbug.com/120903 |
| 556 const char* arguments[] = { command, NULL }; | 557 const char* arguments[] = { command, NULL }; |
| 557 FILE* pipe = NULL; | 558 FILE* pipe = NULL; |
| 558 pid_t pid; | 559 pid_t pid; |
| 559 OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID( | 560 OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID( |
| 560 authorization, | 561 authorization, |
| 561 remoting::kHostHelperTool, | 562 remoting::kHostHelperScriptPath, |
| 562 kAuthorizationFlagDefaults, | 563 kAuthorizationFlagDefaults, |
| 563 arguments, | 564 arguments, |
| 564 &pipe, | 565 &pipe, |
| 565 &pid); | 566 &pid); |
| 566 if (status != errAuthorizationSuccess) { | 567 if (status != errAuthorizationSuccess) { |
| 567 NSLog(@"AuthorizationExecuteWithPrivileges: %s (%d)", | 568 NSLog(@"AuthorizationExecuteWithPrivileges: %s (%d)", |
| 568 GetMacOSStatusErrorString(status), static_cast<int>(status)); | 569 GetMacOSStatusErrorString(status), static_cast<int>(status)); |
| 569 return NO; | 570 return NO; |
| 570 } | 571 } |
| 571 if (pid == -1) { | 572 if (pid == -1) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 error = YES; | 612 error = YES; |
| 612 } | 613 } |
| 613 | 614 |
| 614 // No more cleanup needed. | 615 // No more cleanup needed. |
| 615 if (error) | 616 if (error) |
| 616 return NO; | 617 return NO; |
| 617 | 618 |
| 618 if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) { | 619 if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) { |
| 619 return YES; | 620 return YES; |
| 620 } else { | 621 } else { |
| 621 NSLog(@"%s failed with exit status %d", remoting::kHostHelperTool, | 622 NSLog(@"%s failed with exit status %d", remoting::kHostHelperScriptPath, |
| 622 exit_status); | 623 exit_status); |
| 623 return NO; | 624 return NO; |
| 624 } | 625 } |
| 625 } | 626 } |
| 626 | 627 |
| 627 - (BOOL)sendJobControlMessage:(const char*)launch_key { | 628 - (BOOL)sendJobControlMessage:(const char*)launch_key { |
| 628 base::mac::ScopedLaunchData response( | 629 base::mac::ScopedLaunchData response( |
| 629 base::mac::MessageForJob(kServiceName, launch_key)); | 630 base::mac::MessageForJob(remoting::kServiceName, launch_key)); |
| 630 if (!response) { | 631 if (!response) { |
| 631 NSLog(@"Failed to send message to launchd"); | 632 NSLog(@"Failed to send message to launchd"); |
| 632 [self showError]; | 633 [self showError]; |
| 633 return NO; | 634 return NO; |
| 634 } | 635 } |
| 635 | 636 |
| 636 // Expect a response of type LAUNCH_DATA_ERRNO. | 637 // Expect a response of type LAUNCH_DATA_ERRNO. |
| 637 launch_data_type_t type = launch_data_get_type(response.get()); | 638 launch_data_type_t type = launch_data_get_type(response.get()); |
| 638 if (type != LAUNCH_DATA_ERRNO) { | 639 if (type != LAUNCH_DATA_ERRNO) { |
| 639 NSLog(@"launchd returned unexpected type: %d", type); | 640 NSLog(@"launchd returned unexpected type: %d", type); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 std::string file; | 736 std::string file; |
| 736 if (!GetTemporaryConfigFilePath(&file)) { | 737 if (!GetTemporaryConfigFilePath(&file)) { |
| 737 // There's no point in alerting the user here. The same error would | 738 // There's no point in alerting the user here. The same error would |
| 738 // happen when the pane is eventually restarted, so the user would be | 739 // happen when the pane is eventually restarted, so the user would be |
| 739 // alerted at that time. | 740 // alerted at that time. |
| 740 NSLog(@"Failed to get path of configuration data."); | 741 NSLog(@"Failed to get path of configuration data."); |
| 741 return; | 742 return; |
| 742 } | 743 } |
| 743 | 744 |
| 744 remove(file.c_str()); | 745 remove(file.c_str()); |
| 745 [self notifyPlugin:kUpdateFailedNotificationName]; | 746 [self notifyPlugin:UPDATE_FAILED_NOTIFICATION_NAME]; |
| 746 } | 747 } |
| 747 } | 748 } |
| 748 | 749 |
| 749 - (void)restartSystemPreferences { | 750 - (void)restartSystemPreferences { |
| 750 NSTask* task = [[NSTask alloc] init]; | 751 NSTask* task = [[NSTask alloc] init]; |
| 751 NSString* command = | 752 NSString* command = |
| 752 [NSString stringWithUTF8String:remoting::kHostHelperTool]; | 753 [NSString stringWithUTF8String:remoting::kHostHelperScriptPath]; |
| 753 NSArray* arguments = [NSArray arrayWithObjects:@"--relaunch-prefpane", nil]; | 754 NSArray* arguments = [NSArray arrayWithObjects:@"--relaunch-prefpane", nil]; |
| 754 [task setLaunchPath:command]; | 755 [task setLaunchPath:command]; |
| 755 [task setArguments:arguments]; | 756 [task setArguments:arguments]; |
| 756 [task setStandardInput:[NSPipe pipe]]; | 757 [task setStandardInput:[NSPipe pipe]]; |
| 757 [task launch]; | 758 [task launch]; |
| 758 [task release]; | 759 [task release]; |
| 759 [NSApp terminate:nil]; | 760 [NSApp terminate:nil]; |
| 760 } | 761 } |
| 761 | 762 |
| 762 @end | 763 @end |
| OLD | NEW |