summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorlambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-08 22:47:55 +0000
committerlambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-08 22:47:55 +0000
commitb1636bb28518e391520a90bccc1eb3febf18c3be (patch)
tree89a0ecd7ad0256aba98610fec984383dbde090c5 /remoting
parent1f7f8fe0eb8908ea4aee0896a6f93d62fcb440ff (diff)
downloadchromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.zip
chromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.tar.gz
chromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.tar.bz2
Preference Pane for chromoting on Mac
This adds a new System Preference pane, which is shown when a user configures the Chromoting Host via the web-app. This is basically functional, but is not yet properly integrated with the flow of the web-app. I will prepare a separate CL that implements notifications from the pref-pane back to the web-app. BUG=120903,121749 TEST=Manual Review URL: https://chromiumcodereview.appspot.com/10171020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135934 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/host/installer/mac/ChromotingHostService.packproj19
-rw-r--r--remoting/host/me2me_preference_pane-Info.plist36
-rw-r--r--remoting/host/me2me_preference_pane.h84
-rw-r--r--remoting/host/me2me_preference_pane.mm403
-rw-r--r--remoting/host/me2me_preference_pane.xib1047
-rw-r--r--remoting/host/plugin/daemon_controller_mac.cc190
-rw-r--r--remoting/remoting.gyp59
7 files changed, 1709 insertions, 129 deletions
diff --git a/remoting/host/installer/mac/ChromotingHostService.packproj b/remoting/host/installer/mac/ChromotingHostService.packproj
index 9ad76ae..15e9f0c 100644
--- a/remoting/host/installer/mac/ChromotingHostService.packproj
+++ b/remoting/host/installer/mac/ChromotingHostService.packproj
@@ -217,7 +217,24 @@
</dict>
<dict>
<key>Children</key>
- <array/>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>PreferencePanes/org.chromium.chromoting.prefPane</string>
+ <key>Path Type</key>
+ <integer>2</integer>
+ <key>Privileges</key>
+ <integer>493</integer>
+ <key>Type</key>
+ <integer>3</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
<key>GID</key>
<integer>80</integer>
<key>Path</key>
diff --git a/remoting/host/me2me_preference_pane-Info.plist b/remoting/host/me2me_preference_pane-Info.plist
new file mode 100644
index 0000000..983c206
--- /dev/null
+++ b/remoting/host/me2me_preference_pane-Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>BUNDLE_ID</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>BUNDLE_NAME</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>VERSION_SHORT</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>VERSION_FULL</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2012 COPYRIGHT_BY All rights reserved.</string>
+ <key>NSMainNibFile</key>
+ <string>me2me_preference_pane</string>
+ <key>NSPrefPaneIconFile</key>
+ <string>chromoting128.png</string>
+ <key>NSPrefPaneIconLabel</key>
+ <string>Me2Me</string>
+ <key>NSPrincipalClass</key>
+ <string>Me2MePreferencePane</string>
+</dict>
+</plist>
diff --git a/remoting/host/me2me_preference_pane.h b/remoting/host/me2me_preference_pane.h
new file mode 100644
index 0000000..2ed986e
--- /dev/null
+++ b/remoting/host/me2me_preference_pane.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+#import <PreferencePanes/PreferencePanes.h>
+#import <SecurityInterface/SFAuthorizationView.h>
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+
+namespace remoting {
+class JsonHostConfig;
+}
+
+@interface Me2MePreferencePane : NSPreferencePane {
+ IBOutlet NSTextField* status_message_;
+ IBOutlet NSButton* disable_button_;
+ IBOutlet NSTextField* pin_instruction_message_;
+ IBOutlet NSTextField* email_;
+ IBOutlet NSTextField* pin_;
+ IBOutlet NSButton* apply_button_;
+ IBOutlet SFAuthorizationView* authorization_view_;
+
+ // Holds the new proposed configuration if a temporary config file is
+ // present.
+ scoped_ptr<remoting::JsonHostConfig> config_;
+
+ NSTimer* service_status_timer_;
+
+ // These flags determine the UI state. These are computed in the
+ // update...Status methods.
+ BOOL is_service_running_;
+ BOOL is_pane_unlocked_;
+
+ // True if a new proposed config file has been loaded into memory.
+ BOOL have_new_config_;
+}
+
+- (void)mainViewDidLoad;
+- (void)willSelect;
+- (void)willUnselect;
+- (IBAction)onDisable:(id)sender;
+- (IBAction)onApply:(id)sender;
+- (void)onNewConfigFile:(NSNotification*)notification;
+- (void)refreshServiceStatus:(NSTimer*)timer;
+- (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view;
+- (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view;
+- (void)updateServiceStatus;
+- (void)updateAuthorizationStatus;
+
+// Read any new config file if present. If a config file is successfully read,
+// this deletes the file and keeps the config data loaded in memory. If this
+// method is called a second time (when the file has been deleted), the current
+// config is remembered, so this method acts as a latch: it can change
+// |have_new_config_| from NO to YES, but never from YES to NO.
+//
+// This scheme means that this method can delete the file immediately (to avoid
+// leaving a stale file around in case of a crash), but this method can safely
+// be called multiple times without forgetting the loaded config. To explicitly
+// forget the current config, set |have_new_config_| to NO.
+- (void)readNewConfig;
+
+// Update all UI controls according to any stored flags and loaded config.
+// This should be called after any sequence of operations that might change the
+// UI state.
+- (void)updateUI;
+
+// Alert the user to a generic error condition.
+- (void)showError;
+
+// Alert the user that the typed PIN is incorrect.
+- (void)showIncorrectPinMessage;
+
+// Save the new config to the system, and either start the service or inform
+// the currently-running service of the new config.
+- (void)applyNewServiceConfig;
+
+- (BOOL)runHelperAsRootWithCommand:(const char*)command
+ inputData:(const std::string&)input_data;
+- (BOOL)sendJobControlMessage:(const char*)launch_key;
+
+@end
diff --git a/remoting/host/me2me_preference_pane.mm b/remoting/host/me2me_preference_pane.mm
new file mode 100644
index 0000000..d092983
--- /dev/null
+++ b/remoting/host/me2me_preference_pane.mm
@@ -0,0 +1,403 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "remoting/host/me2me_preference_pane.h"
+
+#import <Cocoa/Cocoa.h>
+#include <launch.h>
+#import <PreferencePanes/PreferencePanes.h>
+#import <SecurityInterface/SFAuthorizationView.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/mac/authorization_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/launchd.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_launch_data.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
+#include "base/sys_string_conversions.h"
+#include "remoting/host/host_config.h"
+#include "remoting/host/json_host_config.h"
+#include "remoting/protocol/me2me_host_authenticator_factory.h"
+
+namespace {
+// The name of the Remoting Host service that is registered with launchd.
+#define kServiceName "org.chromium.chromoting"
+#define kConfigDir "/Library/PrivilegedHelperTools/"
+
+// This helper script is executed as root. It is passed a command-line option
+// (--enable or --disable), which causes it to create or remove a file that
+// informs the host's launch script of whether the host is enabled or disabled.
+const char kHelperTool[] = kConfigDir kServiceName ".me2me.sh";
+
+bool GetTemporaryConfigFilePath(FilePath* path) {
+ if (!file_util::GetTempDir(path))
+ return false;
+ *path = path->Append(kServiceName ".json");
+ return true;
+}
+
+bool IsConfigValid(const remoting::JsonHostConfig* config) {
+ std::string value;
+ return (config->GetString(remoting::kHostIdConfigPath, &value) &&
+ config->GetString(remoting::kHostSecretHashConfigPath, &value) &&
+ config->GetString(remoting::kXmppLoginConfigPath, &value));
+}
+
+bool IsPinValid(const std::string& pin, const std::string& host_id,
+ const std::string& host_secret_hash) {
+ remoting::protocol::SharedSecretHash hash;
+ if (!hash.Parse(host_secret_hash)) {
+ LOG(ERROR) << "Invalid host_secret_hash.";
+ return false;
+ }
+ std::string result =
+ remoting::protocol::AuthenticationMethod::ApplyHashFunction(
+ hash.hash_function, host_id, pin);
+ return result == hash.value;
+}
+
+} // namespace
+
+
+@implementation Me2MePreferencePane
+
+- (void)mainViewDidLoad {
+ [authorization_view_ setDelegate:self];
+ [authorization_view_ setString:kAuthorizationRightExecute];
+ [authorization_view_ setAutoupdate:YES];
+}
+
+- (void)willSelect {
+ have_new_config_ = NO;
+
+ NSDistributedNotificationCenter* center =
+ [NSDistributedNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(onNewConfigFile:)
+ name:@kServiceName
+ object:nil];
+
+ service_status_timer_ =
+ [[NSTimer scheduledTimerWithTimeInterval:2.0
+ target:self
+ selector:@selector(refreshServiceStatus:)
+ userInfo:nil
+ repeats:YES] retain];
+ [self updateServiceStatus];
+ [self updateAuthorizationStatus];
+ [self readNewConfig];
+ [self updateUI];
+}
+
+- (void)willUnselect {
+ NSDistributedNotificationCenter* center =
+ [NSDistributedNotificationCenter defaultCenter];
+ [center removeObserver:self];
+
+ [service_status_timer_ invalidate];
+ [service_status_timer_ release];
+ service_status_timer_ = nil;
+}
+
+- (void)onApply:(id)sender {
+ if (!have_new_config_) {
+ // It shouldn't be possible to hit the button if there is no config to
+ // apply, but check anyway just in case it happens somehow.
+ return;
+ }
+
+ // Ensure the authorization token is up-to-date before using it.
+ [self updateAuthorizationStatus];
+ [self updateUI];
+
+ std::string pin = base::SysNSStringToUTF8([pin_ stringValue]);
+ std::string host_id, host_secret_hash;
+ bool result = (config_->GetString(remoting::kHostIdConfigPath, &host_id) &&
+ config_->GetString(remoting::kHostSecretHashConfigPath,
+ &host_secret_hash));
+ DCHECK(result);
+ if (!IsPinValid(pin, host_id, host_secret_hash)) {
+ [self showIncorrectPinMessage];
+ return;
+ }
+
+ [self applyNewServiceConfig];
+ [self updateUI];
+}
+
+- (void)onDisable:(id)sender {
+ // Ensure the authorization token is up-to-date before using it.
+ [self updateAuthorizationStatus];
+ [self updateUI];
+ if (!is_pane_unlocked_)
+ return;
+
+ if (![self runHelperAsRootWithCommand:"--disable"
+ inputData:""]) {
+ LOG(ERROR) << "Failed to run the helper tool";
+ [self showError];
+ return;
+ }
+
+ // Stop the launchd job. This cannot easily be done by the helper tool,
+ // since the launchd job runs in the current user's context.
+ [self sendJobControlMessage:LAUNCH_KEY_STOPJOB];
+}
+
+- (void)onNewConfigFile:(NSNotification*)notification {
+ [self readNewConfig];
+ [self updateUI];
+}
+
+- (void)refreshServiceStatus:(NSTimer*)timer {
+ BOOL was_running = is_service_running_;
+ [self updateServiceStatus];
+ if (was_running != is_service_running_)
+ [self updateUI];
+}
+
+- (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view {
+ [self updateAuthorizationStatus];
+ [self updateUI];
+}
+
+- (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view {
+ [self updateAuthorizationStatus];
+ [self updateUI];
+}
+
+- (void)updateServiceStatus {
+ pid_t job_pid = base::mac::PIDForJob(kServiceName);
+ is_service_running_ = (job_pid > 0);
+}
+
+- (void)updateAuthorizationStatus {
+ is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_];
+}
+
+- (void)readNewConfig {
+ FilePath file;
+ if (!GetTemporaryConfigFilePath(&file)) {
+ LOG(ERROR) << "Failed to get path of configuration data.";
+ [self showError];
+ return;
+ }
+ if (!file_util::PathExists(file))
+ return;
+
+ scoped_ptr<remoting::JsonHostConfig> new_config_(
+ new remoting::JsonHostConfig(file));
+ if (!new_config_->Read()) {
+ // Report the error, because the file exists but couldn't be read. The
+ // case of non-existence is normal and expected.
+ LOG(ERROR) << "Error reading configuration data from " << file.value();
+ [self showError];
+ return;
+ }
+ file_util::Delete(file, false);
+ if (!IsConfigValid(new_config_.get())) {
+ LOG(ERROR) << "Invalid configuration data read.";
+ [self showError];
+ return;
+ }
+
+ config_.swap(new_config_);
+ have_new_config_ = YES;
+}
+
+- (void)updateUI {
+ // TODO(lambroslambrou): These strings should be localized.
+#ifdef OFFICIAL_BUILD
+ NSString* name = @"Chrome Remote Desktop";
+#else
+ NSString* name = @"Chromoting";
+#endif
+ NSString* message;
+ if (is_service_running_) {
+ message = [NSString stringWithFormat:@"%@ is enabled", name];
+ } else {
+ message = [NSString stringWithFormat:@"%@ is disabled", name];
+ }
+ [status_message_ setStringValue:message];
+
+ std::string email;
+ if (config_.get()) {
+ bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email);
+
+ // The config has already been checked by |IsConfigValid|.
+ DCHECK(result);
+ }
+ [email_ setStringValue:base::SysUTF8ToNSString(email)];
+
+ [disable_button_ setEnabled:(is_pane_unlocked_ && is_service_running_)];
+ [pin_instruction_message_ setEnabled:have_new_config_];
+ [email_ setEnabled:have_new_config_];
+ [pin_ setEnabled:have_new_config_];
+ [apply_button_ setEnabled:(is_pane_unlocked_ && have_new_config_)];
+}
+
+- (void)showError {
+ NSAlert* alert = [[NSAlert alloc] init];
+ [alert setMessageText:@"An unexpected error occurred."];
+ [alert setInformativeText:@"Check the system log for more information."];
+ [alert setAlertStyle:NSWarningAlertStyle];
+ [alert beginSheetModalForWindow:[[self mainView] window]
+ modalDelegate:nil
+ didEndSelector:nil
+ contextInfo:nil];
+ [alert release];
+}
+
+- (void)showIncorrectPinMessage {
+ NSAlert* alert = [[NSAlert alloc] init];
+ [alert setMessageText:@"Incorrect PIN entered."];
+ [alert setAlertStyle:NSWarningAlertStyle];
+ [alert beginSheetModalForWindow:[[self mainView] window]
+ modalDelegate:nil
+ didEndSelector:nil
+ contextInfo:nil];
+ [alert release];
+}
+
+- (void)applyNewServiceConfig {
+ [self updateServiceStatus];
+ std::string serialized_config = config_->GetSerializedData();
+ const char* command = is_service_running_ ? "--save-config" : "--enable";
+ if (![self runHelperAsRootWithCommand:command
+ inputData:serialized_config]) {
+ LOG(ERROR) << "Failed to run the helper tool";
+ [self showError];
+ return;
+ }
+
+ have_new_config_ = NO;
+
+ // If the service is running, send a signal to cause it to reload its
+ // configuration, otherwise start the service.
+ if (is_service_running_) {
+ pid_t job_pid = base::mac::PIDForJob(kServiceName);
+ if (job_pid > 0) {
+ kill(job_pid, SIGHUP);
+ } else {
+ LOG(ERROR) << "Failed to obtain PID of service " << kServiceName;
+ [self showError];
+ }
+ } else {
+ [self sendJobControlMessage:LAUNCH_KEY_STARTJOB];
+ }
+}
+
+- (BOOL)runHelperAsRootWithCommand:(const char*)command
+ inputData:(const std::string&)input_data {
+ AuthorizationRef authorization =
+ [[authorization_view_ authorization] authorizationRef];
+ if (!authorization) {
+ LOG(ERROR) << "Failed to obtain authorizationRef";
+ return NO;
+ }
+
+ // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges
+ // call with a launchd-based helper tool, which is more secure.
+ // http://crbug.com/120903
+ const char* arguments[] = { command, NULL };
+ FILE* pipe = NULL;
+ pid_t pid;
+ OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID(
+ authorization,
+ kHelperTool,
+ kAuthorizationFlagDefaults,
+ arguments,
+ &pipe,
+ &pid);
+ if (status != errAuthorizationSuccess) {
+ OSSTATUS_LOG(ERROR, status) << "AuthorizationExecuteWithPrivileges";
+ return NO;
+ }
+ if (pid == -1) {
+ LOG(ERROR) << "Failed to get child PID";
+ if (pipe)
+ fclose(pipe);
+
+ return NO;
+ }
+ if (!pipe) {
+ LOG(ERROR) << "Unexpected NULL pipe";
+ return NO;
+ }
+
+ // Some cleanup is needed (closing the pipe and waiting for the child
+ // process), so flag any errors before returning.
+ BOOL error = NO;
+
+ if (!input_data.empty()) {
+ size_t bytes_written = fwrite(input_data.data(), sizeof(char),
+ input_data.size(), pipe);
+ // According to the fwrite manpage, a partial count is returned only if a
+ // write error has occurred.
+ if (bytes_written != input_data.size()) {
+ LOG(ERROR) << "Failed to write data to child process";
+ error = YES;
+ }
+ }
+
+ // In all cases, fclose() should be called with the returned FILE*. In the
+ // case of sending data to the child, this needs to be done before calling
+ // waitpid(), since the child reads until EOF on its stdin, so calling
+ // waitpid() first would result in deadlock.
+ if (fclose(pipe) != 0) {
+ PLOG(ERROR) << "fclose";
+ error = YES;
+ }
+
+ int exit_status;
+ pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0));
+ if (wait_result != pid) {
+ PLOG(ERROR) << "waitpid";
+ error = YES;
+ }
+
+ // No more cleanup needed.
+ if (error)
+ return NO;
+
+ if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) {
+ return YES;
+ } else {
+ LOG(ERROR) << kHelperTool << " failed with exit status " << exit_status;
+ return NO;
+ }
+}
+
+- (BOOL)sendJobControlMessage:(const char*)launch_key {
+ base::mac::ScopedLaunchData response(
+ base::mac::MessageForJob(kServiceName, launch_key));
+ if (!response) {
+ LOG(ERROR) << "Failed to send message to launchd";
+ [self showError];
+ return NO;
+ }
+
+ // Expect a response of type LAUNCH_DATA_ERRNO.
+ launch_data_type_t type = launch_data_get_type(response.get());
+ if (type != LAUNCH_DATA_ERRNO) {
+ LOG(ERROR) << "launchd returned unexpected type: " << type;
+ [self showError];
+ return NO;
+ }
+
+ int error = launch_data_get_errno(response.get());
+ if (error) {
+ LOG(ERROR) << "launchd returned error: " << error;
+ [self showError];
+ return NO;
+ }
+ return YES;
+}
+
+@end
diff --git a/remoting/host/me2me_preference_pane.xib b/remoting/host/me2me_preference_pane.xib
new file mode 100644
index 0000000..f433f2d
--- /dev/null
+++ b/remoting/host/me2me_preference_pane.xib
@@ -0,0 +1,1047 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">10K549</string>
+ <string key="IBDocument.InterfaceBuilderVersion">851</string>
+ <string key="IBDocument.AppKitVersion">1038.36</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">851</string>
+ </object>
+ <array class="NSMutableArray" key="IBDocument.EditedObjectIDs"/>
+ <array key="IBDocument.PluginDependencies">
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </array>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <array class="NSMutableArray" key="IBDocument.RootObjects" id="409411428">
+ <object class="NSCustomObject" id="294453543">
+ <string key="NSClassName">Me2MePreferencePane</string>
+ </object>
+ <object class="NSCustomObject" id="308860122">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="278121016">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="660800786">
+ <int key="NSWindowStyleMask">7</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{176, 715}, {667, 292}}</string>
+ <int key="NSWTFlags">1081606144</int>
+ <string key="NSWindowTitle">&lt;&lt; do not localize &gt;&gt;</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ <string key="NSWindowContentMinSize">{224.664, 10}</string>
+ <object class="NSView" key="NSWindowView" id="1037298196">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <array class="NSMutableArray" key="NSSubviews">
+ <object class="NSButton" id="1007314448">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">298</int>
+ <string key="NSFrame">{{293, 88}, {82, 32}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="987594175">
+ <int key="NSCellFlags">604110336</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Apply</string>
+ <object class="NSFont" key="NSSupport" id="819947481">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="1007314448"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="963034143">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">298</int>
+ <string key="NSFrame">{{87, 154}, {494, 17}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="165875597">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">138413056</int>
+ <string key="NSContents">email</string>
+ <reference key="NSSupport" ref="819947481"/>
+ <reference key="NSControlView" ref="963034143"/>
+ <object class="NSColor" key="NSBackgroundColor" id="436039819">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="666068957">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor" id="311176931">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="85957345">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">298</int>
+ <string key="NSFrame">{{240, 124}, {187, 22}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="785807768">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="819947481"/>
+ <reference key="NSControlView" ref="85957345"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textColor</string>
+ <reference key="NSColor" ref="311176931"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSCustomView" id="737813299">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">303</int>
+ <string key="NSFrame">{{20, 20}, {627, 47}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <string key="NSClassName">SFAuthorizationView</string>
+ </object>
+ <object class="NSTextField" id="345845398">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">298</int>
+ <string key="NSFrame">{{86, 255}, {494, 17}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="101917910">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">138413056</int>
+ <string key="NSContents">Status text</string>
+ <reference key="NSSupport" ref="819947481"/>
+ <reference key="NSControlView" ref="345845398"/>
+ <reference key="NSBackgroundColor" ref="436039819"/>
+ <reference key="NSTextColor" ref="666068957"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="441586301">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">298</int>
+ <string key="NSFrame">{{86, 179}, {494, 17}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="146146078">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">138413056</int>
+ <string key="NSContents">Please confirm PIN for user:</string>
+ <reference key="NSSupport" ref="819947481"/>
+ <reference key="NSControlView" ref="441586301"/>
+ <reference key="NSBackgroundColor" ref="436039819"/>
+ <reference key="NSTextColor" ref="666068957"/>
+ </object>
+ </object>
+ <object class="NSButton" id="331564268">
+ <reference key="NSNextResponder" ref="1037298196"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{240, 219}, {186, 32}}</string>
+ <reference key="NSSuperview" ref="1037298196"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="448132067">
+ <int key="NSCellFlags">604110336</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Disable Remote Access</string>
+ <reference key="NSSupport" ref="819947481"/>
+ <reference key="NSControlView" ref="331564268"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </array>
+ <string key="NSFrameSize">{667, 292}</string>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {2560, 1578}}</string>
+ <string key="NSMinSize">{224.664, 32}</string>
+ <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ </object>
+ </array>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <array class="NSMutableArray" key="connectionRecords">
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_window</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="660800786"/>
+ </object>
+ <int key="connectionID">26</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">authorization_view_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="737813299"/>
+ </object>
+ <int key="connectionID">108</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">status_message_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="345845398"/>
+ </object>
+ <int key="connectionID">111</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">email_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="963034143"/>
+ </object>
+ <int key="connectionID">114</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">apply_button_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="1007314448"/>
+ </object>
+ <int key="connectionID">115</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">onApply:</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="1007314448"/>
+ </object>
+ <int key="connectionID">116</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">pin_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="85957345"/>
+ </object>
+ <int key="connectionID">117</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">disable_button_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="331564268"/>
+ </object>
+ <int key="connectionID">120</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">pin_instruction_message_</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="441586301"/>
+ </object>
+ <int key="connectionID">121</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">onDisable:</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="331564268"/>
+ </object>
+ <int key="connectionID">122</int>
+ </object>
+ </array>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <array key="orderedObjects">
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <array key="object" id="0"/>
+ <reference key="children" ref="409411428"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="294453543"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="308860122"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="660800786"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="1037298196"/>
+ </array>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">PrefPane</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">6</int>
+ <reference key="object" ref="1037298196"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="345845398"/>
+ <reference ref="737813299"/>
+ <reference ref="1007314448"/>
+ <reference ref="963034143"/>
+ <reference ref="331564268"/>
+ <reference ref="85957345"/>
+ <reference ref="441586301"/>
+ </array>
+ <reference key="parent" ref="660800786"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="278121016"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">99</int>
+ <reference key="object" ref="1007314448"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="987594175"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">100</int>
+ <reference key="object" ref="987594175"/>
+ <reference key="parent" ref="1007314448"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">101</int>
+ <reference key="object" ref="963034143"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="165875597"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">102</int>
+ <reference key="object" ref="165875597"/>
+ <reference key="parent" ref="963034143"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">103</int>
+ <reference key="object" ref="85957345"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="785807768"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">104</int>
+ <reference key="object" ref="785807768"/>
+ <reference key="parent" ref="85957345"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">105</int>
+ <reference key="object" ref="737813299"/>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">109</int>
+ <reference key="object" ref="345845398"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="101917910"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">110</int>
+ <reference key="object" ref="101917910"/>
+ <reference key="parent" ref="345845398"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">112</int>
+ <reference key="object" ref="441586301"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="146146078"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">113</int>
+ <reference key="object" ref="146146078"/>
+ <reference key="parent" ref="441586301"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">118</int>
+ <reference key="object" ref="331564268"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="448132067"/>
+ </array>
+ <reference key="parent" ref="1037298196"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">119</int>
+ <reference key="object" ref="448132067"/>
+ <reference key="parent" ref="331564268"/>
+ </object>
+ </array>
+ </object>
+ <dictionary class="NSMutableDictionary" key="flattenedProperties">
+ <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="100.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="101.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="102.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="103.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="104.CustomClassName">NSSecureTextFieldCell</string>
+ <string key="104.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="105.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="109.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="110.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="112.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="113.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="118.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="119.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="12.IBEditorWindowLastContentRect">{{0, 1253}, {668, 292}}</string>
+ <string key="12.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="12.IBWindowTemplateEditedContentRect">{{0, 1253}, {668, 292}}</string>
+ <boolean value="YES" key="12.windowTemplate.hasMinSize"/>
+ <string key="12.windowTemplate.minSize">{224.664, 10}</string>
+ <string key="6.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="99.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
+ <nil key="activeLocalization"/>
+ <dictionary class="NSMutableDictionary" key="localizations"/>
+ <nil key="sourceID"/>
+ <int key="maxID">122</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <array class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <object class="IBPartialClassDescription">
+ <string key="className">Me2MePreferencePane</string>
+ <string key="superclassName">NSPreferencePane</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="onApply:">id</string>
+ <string key="onDisable:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="onApply:">
+ <string key="name">onApply:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="onDisable:">
+ <string key="name">onDisable:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="apply_button_">NSButton</string>
+ <string key="authorization_view_">SFAuthorizationView</string>
+ <string key="disable_button_">NSButton</string>
+ <string key="email_">NSTextField</string>
+ <string key="pin_">NSTextField</string>
+ <string key="pin_instruction_message_">NSTextField</string>
+ <string key="status_message_">NSTextField</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="apply_button_">
+ <string key="name">apply_button_</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="authorization_view_">
+ <string key="name">authorization_view_</string>
+ <string key="candidateClassName">SFAuthorizationView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="disable_button_">
+ <string key="name">disable_button_</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="email_">
+ <string key="name">email_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="pin_">
+ <string key="name">pin_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="pin_instruction_message_">
+ <string key="name">pin_instruction_message_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="status_message_">
+ <string key="name">status_message_</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">host/me2me_preference_pane.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">../third_party/GTM/AppKit/GTMCarbonEvent.h</string>
+ </object>
+ </object>
+ </array>
+ <array class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+ <object class="IBPartialClassDescription">
+ <string key="className">NSActionCell</string>
+ <string key="superclassName">NSCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="741398341">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="537953501">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="813691524">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButton</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButtonCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSCell</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSControl</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="161226876">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSFormatter</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMenu</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="924316341">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="741398341"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="537953501"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="813691524"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="161226876"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="924316341"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="464411912">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedAudioOutput.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedVideoOutput.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTCaptureFileOutput.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTCaptureVideoPreviewOutput.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTCaptureView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTMovie.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">QTKit.framework/Headers/QTMovieView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSPreferencePane</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="_firstKeyView">NSView</string>
+ <string key="_initialKeyView">NSView</string>
+ <string key="_lastKeyView">NSView</string>
+ <string key="_window">NSWindow</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="_firstKeyView">
+ <string key="name">_firstKeyView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_initialKeyView">
+ <string key="name">_initialKeyView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_lastKeyView">
+ <string key="name">_lastKeyView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_window">
+ <string key="name">_window</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">PreferencePanes.framework/Headers/NSPreferencePane.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSSecureTextFieldCell</string>
+ <string key="superclassName">NSTextFieldCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSecureTextField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextField</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextFieldCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <string key="superclassName">NSResponder</string>
+ <reference key="sourceIdentifier" ref="464411912"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+ </object>
+ </object>
+ </array>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <real value="1050" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <integer value="1060" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../remoting.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
diff --git a/remoting/host/plugin/daemon_controller_mac.cc b/remoting/host/plugin/daemon_controller_mac.cc
index a75d613..a59c164 100644
--- a/remoting/host/plugin/daemon_controller_mac.cc
+++ b/remoting/host/plugin/daemon_controller_mac.cc
@@ -10,15 +10,14 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
-#include "base/mac/authorization_util.h"
+#include "base/mac/foundation_util.h"
#include "base/mac/launchd.h"
#include "base/mac/mac_logging.h"
-#include "base/mac/scoped_authorizationref.h"
+#include "base/mac/mac_util.h"
#include "base/mac/scoped_launch_data.h"
#include "base/threading/thread.h"
#include "base/time.h"
@@ -29,6 +28,12 @@ namespace remoting {
namespace {
+// The NSSystemDirectories.h header has a conflicting definition of
+// NSSearchPathDirectory with the one in base/mac/foundation_util.h.
+// Foundation.h would work, but it can only be included from Objective-C files.
+// Therefore, we define the needed constants here.
+const int NSLibraryDirectory = 5;
+
// The name of the Remoting Host service that is registered with launchd.
#define kServiceName "org.chromium.chromoting"
#define kConfigDir "/Library/PrivilegedHelperTools/"
@@ -72,13 +77,8 @@ class DaemonControllerMac : public remoting::DaemonController {
void NotifyWhenStopped(const CompletionCallback& done_callback,
int tries_remaining,
const base::TimeDelta& sleep);
+ bool ShowPreferencePane(const std::string& config_data);
- bool RunToolScriptAsRoot(const char* command, const std::string& input_data);
- bool SendJobControlMessage(const char* launchKey);
-
- // The API for gaining root privileges is blocking (it prompts the user for
- // a password). Since Start() and Stop() must not block the main thread, they
- // need to post their tasks to a separate thread.
base::Thread auth_thread_;
DISALLOW_COPY_AND_ASSIGN(DaemonControllerMac);
@@ -90,12 +90,6 @@ DaemonControllerMac::DaemonControllerMac()
}
DaemonControllerMac::~DaemonControllerMac() {
- // This will block if the thread is waiting on a root password prompt. There
- // doesn't seem to be an easy solution for this, other than to spawn a
- // separate process to do the root elevation.
-
- // TODO(lambroslambrou): Improve this, either by finding a way to terminate
- // the thread, or by moving to a separate process.
auth_thread_.Stop();
}
@@ -167,13 +161,11 @@ void DaemonControllerMac::DoGetConfig(const GetConfigCallback& callback) {
void DaemonControllerMac::DoSetConfigAndStart(
scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done_callback) {
- std::string file_content;
- base::JSONWriter::Write(config.get(), &file_content);
- if (!RunToolScriptAsRoot("--enable", file_content)) {
- done_callback.Run(RESULT_FAILED);
- return;
- }
- bool result = SendJobControlMessage(LAUNCH_KEY_STARTJOB);
+ std::string config_data;
+ base::JSONWriter::Write(config.get(), &config_data);
+
+ bool result = ShowPreferencePane(config_data);
+
done_callback.Run(result ? RESULT_OK : RESULT_FAILED);
}
@@ -197,36 +189,65 @@ void DaemonControllerMac::DoUpdateConfig(
config_file.SetString(*key, value);
}
- std::string file_content = config_file.GetSerializedData();
- if (!RunToolScriptAsRoot("--save-config", file_content)) {
- done_callback.Run(RESULT_FAILED);
- return;
+ std::string config_data = config_file.GetSerializedData();
+ bool success = ShowPreferencePane(config_data);
+
+ done_callback.Run(success ? RESULT_OK : RESULT_FAILED);
+}
+
+bool DaemonControllerMac::ShowPreferencePane(const std::string& config_data) {
+ if (!config_data.empty()) {
+ FilePath config_path;
+ if (!file_util::GetTempDir(&config_path)) {
+ LOG(ERROR) << "Failed to get filename for saving configuration data.";
+ return false;
+ }
+ config_path = config_path.Append(kServiceName ".json");
+
+ int written = file_util::WriteFile(config_path, config_data.data(),
+ config_data.size());
+ if (written != static_cast<int>(config_data.size())) {
+ LOG(ERROR) << "Failed to save configuration data to: "
+ << config_path.value();
+ return false;
+ }
}
- done_callback.Run(RESULT_OK);
- pid_t job_pid = base::mac::PIDForJob(kServiceName);
- if (job_pid > 0) {
- kill(job_pid, SIGHUP);
+ FilePath pane_path;
+ // TODO(lambroslambrou): Use NSPreferencePanesDirectory once we start
+ // building against SDK 10.6.
+ if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &pane_path)) {
+ LOG(ERROR) << "Failed to get directory for local preference panes.";
+ return false;
}
-}
+ pane_path = pane_path.Append("PreferencePanes")
+ .Append(kServiceName ".prefPane");
-void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) {
- if (!RunToolScriptAsRoot("--disable", "")) {
- done_callback.Run(RESULT_FAILED);
- return;
+ FSRef pane_path_ref;
+ if (!base::mac::FSRefFromPath(pane_path.value(), &pane_path_ref)) {
+ LOG(ERROR) << "Failed to create FSRef";
+ return false;
+ }
+ OSStatus status = LSOpenFSRef(&pane_path_ref, NULL);
+ if (status != noErr) {
+ OSSTATUS_LOG(ERROR, status) << "LSOpenFSRef failed for path: "
+ << pane_path.value();
+ return false;
}
- // Deleting the trigger file does not cause launchd to stop the service.
- // Since the service is running for the local user's desktop (not as root),
- // it has to be stopped for that user. This cannot easily be done in the
- // shell-script running as root, so it is done here instead.
- if (!SendJobControlMessage(LAUNCH_KEY_STOPJOB)) {
+ CFNotificationCenterRef center =
+ CFNotificationCenterGetDistributedCenter();
+ CFNotificationCenterPostNotification(center, CFSTR(kServiceName), NULL, NULL,
+ TRUE);
+ return true;
+}
+
+void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) {
+ if (!ShowPreferencePane("")) {
done_callback.Run(RESULT_FAILED);
return;
}
- // SendJobControlMessage does not wait for the stop to take effect, so we
- // can't return immediately. Instead, we wait up to 10s.
NotifyWhenStopped(done_callback,
kStopWaitRetryLimit,
base::TimeDelta::FromMilliseconds(kStopWaitTimeout));
@@ -252,91 +273,6 @@ void DaemonControllerMac::NotifyWhenStopped(
}
}
-bool DaemonControllerMac::RunToolScriptAsRoot(const char* command,
- const std::string& input_data) {
- // TODO(lambroslambrou): Supply a localized prompt string here.
- base::mac::ScopedAuthorizationRef authorization(
- base::mac::AuthorizationCreateToRunAsRoot(CFSTR("")));
- if (!authorization) {
- LOG(ERROR) << "Failed to get root privileges.";
- return false;
- }
-
- if (!file_util::VerifyPathControlledByAdmin(FilePath(kStartStopTool))) {
- LOG(ERROR) << "Security check failed for: " << kStartStopTool;
- return false;
- }
-
- // TODO(lambroslambrou): Use sandbox-exec to minimize exposure -
- // http://crbug.com/120903
- const char* arguments[] = { command, NULL };
- FILE* pipe = NULL;
- pid_t pid;
- OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID(
- authorization.get(),
- kStartStopTool,
- kAuthorizationFlagDefaults,
- arguments,
- &pipe,
- &pid);
- if (status != errAuthorizationSuccess) {
- OSSTATUS_LOG(ERROR, status) << "AuthorizationExecuteWithPrivileges";
- return false;
- }
- if (pid == -1) {
- LOG(ERROR) << "Failed to get child PID";
- return false;
- }
-
- DCHECK(pipe);
- if (!input_data.empty()) {
- size_t bytes_written = fwrite(input_data.data(), sizeof(char),
- input_data.size(), pipe);
- // According to the fwrite manpage, a partial count is returned only if a
- // write error has occurred.
- if (bytes_written != input_data.size()) {
- LOG(ERROR) << "Failed to write data to child process";
- }
- // Need to close, since the child waits for EOF on its stdin.
- if (fclose(pipe) != 0) {
- PLOG(ERROR) << "fclose";
- }
- }
-
- int exit_status;
- pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0));
- if (wait_result != pid) {
- PLOG(ERROR) << "waitpid";
- return false;
- }
- if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) {
- return true;
- } else {
- LOG(ERROR) << kStartStopTool << " failed with exit status " << exit_status;
- return false;
- }
-}
-
-bool DaemonControllerMac::SendJobControlMessage(const char* launchKey) {
- base::mac::ScopedLaunchData response(
- base::mac::MessageForJob(kServiceName, launchKey));
- if (!response) {
- LOG(ERROR) << "Failed to send message to launchd";
- return false;
- }
-
- // Got a response, so check if launchd sent a non-zero error code, otherwise
- // assume the command was successful.
- if (launch_data_get_type(response.get()) == LAUNCH_DATA_ERRNO) {
- int error = launch_data_get_errno(response.get());
- if (error) {
- LOG(ERROR) << "launchd returned error " << error;
- return false;
- }
- }
- return true;
-}
-
} // namespace
scoped_ptr<DaemonController> remoting::DaemonController::Create() {
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index e357c7dd..e1258ef 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -286,8 +286,9 @@
'target_name': 'remoting_me2me_host_archive',
'type': 'none',
'dependencies': [
- 'remoting_me2me_host',
+ 'remoting_host_prefpane',
'remoting_host_uninstaller',
+ 'remoting_me2me_host',
],
'sources': [
'host/installer/build-installer-archive.py',
@@ -318,10 +319,12 @@
'temp_dir': '<(SHARED_INTERMEDIATE_DIR)/remoting/remoting-me2me-host',
'zip_path': '<(PRODUCT_DIR)/remoting-me2me-host-<(OS).zip',
'generated_files': [
+ '<(PRODUCT_DIR)/remoting_host_prefpane.prefPane',
'<(PRODUCT_DIR)/remoting_me2me_host',
'<(PRODUCT_DIR)/remoting_host_uninstaller.app',
],
'generated_files_dst': [
+ 'PreferencePanes/org.chromium.chromoting.prefPane',
'PrivilegedHelperTools/org.chromium.chromoting.me2me_host',
'Applications/<(host_uninstaller_name).app',
],
@@ -372,6 +375,60 @@
},
], # actions
}, # end of target 'remoting_me2me_host_archive'
+
+ {
+ 'target_name': 'remoting_host_prefpane',
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ 'product_extension': 'prefPane',
+ 'dependencies': [
+ 'remoting_base',
+ 'remoting_host',
+ ],
+ 'sources': [
+ 'host/me2me_preference_pane.h',
+ 'host/me2me_preference_pane.mm',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/PreferencePanes.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'host/me2me_preference_pane-Info.plist',
+ 'INFOPLIST_PREPROCESS': 'YES',
+ 'INFOPLIST_PREPROCESSOR_DEFINITIONS': 'VERSION_FULL="<(version_full)" VERSION_SHORT="<(version_short)" BUNDLE_NAME="<(bundle_name)" BUNDLE_ID="<(bundle_id)" COPYRIGHT_BY="<(copyright_by)"',
+ },
+ 'mac_bundle_resources': [
+ 'host/me2me_preference_pane.xib',
+ 'host/me2me_preference_pane-Info.plist',
+ 'resources/chromoting128.png',
+ ],
+ 'mac_bundle_resources!': [
+ 'host/me2me_preference_pane-Info.plist',
+ ],
+ 'conditions': [
+ ['mac_breakpad==1', {
+ 'variables': {
+ # A real .dSYM is needed for dump_syms to operate on.
+ 'mac_real_dsym': 1,
+ },
+ }],
+ ['branding == "Chrome"', {
+ 'variables': {
+ 'copyright_by': 'Google Inc.',
+ 'bundle_id': 'com.google.chromeremotedesktop.preferences',
+ 'bundle_name': 'Chrome Remote Desktop Host Preferences',
+ },
+ }, { # else branding!="Chrome"
+ 'variables': {
+ 'copyright_by': 'The Chromium Authors.',
+ 'bundle_id': 'org.chromium.remoting.preferences',
+ 'bundle_name': 'Chromoting Host Preferences',
+ },
+ }],
+ ], # conditions
+ }, # end of target 'remoting_host_prefpane'
], # end of 'targets'
}], # 'OS=="mac"'