Index: mojo/shell/shell.cc |
diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc |
index 087c0be1a02207e2577cc99b5d7126528b40752e..21f1e13d45ba00d0d676d08a5cbb1d98523d33f1 100644 |
--- a/mojo/shell/shell.cc |
+++ b/mojo/shell/shell.cc |
@@ -125,20 +125,28 @@ class Shell::Instance : public mojom::Connector, |
Array<String>::From(interfaces), params->target().name()); |
} |
- scoped_ptr<NativeRunner> StartWithFileURL(const GURL& file_url, |
- mojom::ShellClientRequest request, |
- bool start_sandboxed, |
- NativeRunnerFactory* factory) { |
- base::FilePath path = util::UrlToFilePath(file_url); |
- scoped_ptr<NativeRunner> runner = factory->Create(path); |
- runner_ = runner.get(); |
- runner_->Start(path, identity_, start_sandboxed, std::move(request), |
- base::Bind(&Instance::PIDAvailable, |
- weak_factory_.GetWeakPtr()), |
- base::Bind(&mojo::shell::Shell::CleanupRunner, |
- shell_->weak_ptr_factory_.GetWeakPtr(), |
- runner_)); |
- return runner; |
+ void StartWithClientProcessConnection( |
+ mojom::ShellClientRequest request, |
+ mojom::ClientProcessConnectionPtr client_process_connection) { |
+ factory_.Bind(mojom::ShellClientFactoryPtrInfo( |
+ std::move(client_process_connection->shell_client_factory), 0u)); |
+ pid_receiver_binding_.Bind( |
+ std::move(client_process_connection->pid_receiver_request)); |
+ factory_->CreateShellClient(std::move(request), identity_.name()); |
+ } |
+ |
+ void StartWithFilePath(mojom::ShellClientRequest request, |
+ const base::FilePath& path) { |
+ scoped_ptr<NativeRunner> runner = |
+ shell_->native_runner_factory_->Create(path); |
+ bool start_sandboxed = false; |
+ runner->Start(path, identity_, start_sandboxed, std::move(request), |
+ base::Bind(&Instance::PIDAvailable, |
+ weak_factory_.GetWeakPtr()), |
+ base::Bind(&mojo::shell::Shell::CleanupRunner, |
+ shell_->weak_ptr_factory_.GetWeakPtr(), |
+ runner.get())); |
+ shell_->native_runners_.push_back(std::move(runner)); |
} |
mojom::InstanceInfoPtr CreateInstanceInfo() const { |
@@ -160,40 +168,34 @@ class Shell::Instance : public mojom::Connector, |
private: |
// mojom::Connector implementation: |
- void Connect(mojom::IdentityPtr target, |
+ void Connect(mojom::IdentityPtr target_ptr, |
mojom::InterfaceProviderRequest remote_interfaces, |
mojom::InterfaceProviderPtr local_interfaces, |
+ mojom::ClientProcessConnectionPtr client_process_connection, |
const ConnectCallback& callback) override { |
- if (!IsValidName(target->name)) { |
- LOG(ERROR) << "Error: invalid Name: " << target->name; |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ Identity target = target_ptr.To<Identity>(); |
+ if (!ValidateIdentity(target, callback)) |
return; |
- } |
- if (!base::IsValidGUID(target->user_id)) { |
- LOG(ERROR) << "Error: invalid user_id: " << target->user_id; |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ if (!ValidateClientProcessConnection(&client_process_connection, target, |
+ callback)) { |
return; |
} |
- // TODO(beng): perform checking on policy of whether this instance is |
- // allowed to pass different user_ids. |
- // TODO(beng): perform checking on policy of whether this instance is |
- // allowed to pass non-empty instance identifiers. |
- if (allow_any_application_ || filter_.find(target->name) != filter_.end()) { |
- scoped_ptr<ConnectParams> params(new ConnectParams); |
- params->set_source(identity_); |
- params->set_target(target.To<Identity>()); |
- params->set_remote_interfaces(std::move(remote_interfaces)); |
- params->set_local_interfaces(std::move(local_interfaces)); |
- params->set_connect_callback(callback); |
- shell_->Connect(std::move(params)); |
- } else { |
- LOG(WARNING) << "CapabilityFilter prevented connection from: " << |
- identity_.name() << " to: " << target->name; |
- callback.Run(mojom::ConnectResult::ACCESS_DENIED, |
- mojom::kInheritUserID, mojom::kInvalidInstanceID); |
- } |
+ // TODO(beng): Need to do the following additional policy validation of |
+ // whether this instance is allowed to connect using: |
+ // - a user id other than its own, kInheritUserID or kRootUserID. |
+ // - a non-empty instance name. |
+ // - a non-null client_process_connection. |
+ if (!ValidateCapabilityFilter(target, callback)) |
+ return; |
+ |
+ scoped_ptr<ConnectParams> params(new ConnectParams); |
+ params->set_source(identity_); |
+ params->set_target(target); |
+ params->set_remote_interfaces(std::move(remote_interfaces)); |
+ params->set_local_interfaces(std::move(local_interfaces)); |
+ params->set_client_process_connection(std::move(client_process_connection)); |
+ params->set_connect_callback(callback); |
+ shell_->Connect(std::move(params)); |
} |
void Clone(mojom::ConnectorRequest request) override { |
connectors_.AddBinding(this, std::move(request)); |
@@ -211,54 +213,67 @@ class Shell::Instance : public mojom::Connector, |
} |
// mojom::Shell implementation: |
- void CreateInstance(mojom::ShellClientFactoryPtr factory, |
- mojom::IdentityPtr target, |
- mojom::PIDReceiverRequest pid_receiver, |
- const CreateInstanceCallback& callback) override { |
- // We need to bounce through the package manager to load the |
- // CapabilityFilter. |
- std::string name = target->name; |
- shell_->shell_resolver_->ResolveMojoName(name, base::Bind( |
- &mojo::shell::Shell::Instance::OnResolvedNameForCreateInstance, |
- weak_factory_.GetWeakPtr(), base::Passed(std::move(factory)), |
- base::Passed(std::move(target)), base::Passed(std::move(pid_receiver)), |
- callback)); |
- } |
void AddInstanceListener(mojom::InstanceListenerPtr listener) override { |
// TODO(beng): this should only track the instances matching this user, and |
// root. |
shell_->AddInstanceListener(std::move(listener)); |
} |
- void OnResolvedNameForCreateInstance(mojom::ShellClientFactoryPtr factory, |
- mojom::IdentityPtr target, |
- mojom::PIDReceiverRequest pid_receiver, |
- const CreateInstanceCallback& callback, |
- const String& resolved_name, |
- const String& resolved_instance, |
- mojom::CapabilityFilterPtr filter, |
- const String& file_url) { |
- if (!base::IsValidGUID(target->user_id)) |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT); |
- |
- Identity target_id = target.To<Identity>(); |
- |
- // TODO(beng): perform checking on policy of whether this instance is |
- // allowed to pass different user_ids. |
- if (target_id.user_id() == mojom::kInheritUserID) |
- target_id.set_user_id(identity_.user_id()); |
- |
- mojom::ShellClientRequest request; |
- Instance* instance = shell_->CreateInstance( |
- target_id, filter->filter.To<CapabilityFilter>(), &request); |
- instance->pid_receiver_binding_.Bind(std::move(pid_receiver)); |
- instance->factory_ = std::move(factory); |
- instance->factory_->CreateShellClient(std::move(request), target->name); |
- callback.Run(mojom::ConnectResult::SUCCEEDED); |
- // We don't call ConnectToClient() here since the instance was created |
- // manually by other code, not in response to a Connect() request. The newly |
- // created instance is identified by |name| and may be subsequently reached |
- // by client code using this identity. |
+ bool ValidateIdentity(const Identity& identity, |
+ const ConnectCallback& callback) { |
+ if (!IsValidName(identity.name())) { |
+ LOG(ERROR) << "Error: invalid Name: " << identity.name(); |
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
+ mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ return false; |
+ } |
+ if (!base::IsValidGUID(identity.user_id())) { |
+ LOG(ERROR) << "Error: invalid user_id: " << identity.user_id(); |
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
+ mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ bool ValidateClientProcessConnection( |
+ mojom::ClientProcessConnectionPtr* client_process_connection, |
+ const Identity& identity, |
+ const ConnectCallback& callback) { |
+ if (!client_process_connection->is_null()) { |
+ if (!(*client_process_connection)->shell_client_factory.is_valid() || |
+ !(*client_process_connection)->pid_receiver_request.is_valid()) { |
+ LOG(ERROR) << "Error: must supply both shell_client_factory AND " |
+ << "pid_receiver_request when sending " |
+ << "client_process_connection."; |
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
+ mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ return false; |
+ } |
+ if (shell_->GetExistingOrRootInstance(identity)) { |
+ LOG(ERROR) << "Error: Cannot client process matching existing identity:" |
+ << "Name: " << identity.name() << " User: " |
+ << identity.user_id() << " Instance: " |
+ << identity.instance(); |
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
+ mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ bool ValidateCapabilityFilter(const Identity& target, |
+ const ConnectCallback& callback) { |
+ if (allow_any_application_ || |
+ filter_.find(target.name()) != filter_.end()) { |
+ return true; |
+ } |
+ LOG(ERROR) << "CapabilityFilter prevented connection from: " << |
+ identity_.name() << " to: " << target.name(); |
+ callback.Run(mojom::ConnectResult::ACCESS_DENIED, |
+ mojom::kInheritUserID, mojom::kInvalidInstanceID); |
+ return false; |
} |
uint32_t GenerateUniqueID() const { |
@@ -456,6 +471,17 @@ Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const { |
return it != identity_to_instance_.end() ? it->second : nullptr; |
} |
+Shell::Instance* Shell::GetExistingOrRootInstance( |
+ const Identity& identity) const { |
+ Instance* instance = GetExistingInstance(identity); |
+ if (!instance) { |
+ Identity root_identity = identity; |
+ root_identity.set_user_id(mojom::kRootUserID); |
+ instance = GetExistingInstance(root_identity); |
+ } |
+ return instance; |
+} |
+ |
void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) { |
instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) { |
listener->InstancePIDAvailable(id, pid); |
@@ -463,15 +489,10 @@ void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) { |
} |
bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { |
- Instance* instance = GetExistingInstance((*params)->target()); |
- if (!instance) { |
- Identity root_identity = (*params)->target(); |
- root_identity.set_user_id(mojom::kRootUserID); |
- instance = GetExistingInstance(root_identity); |
- if (!instance) return false; |
- } |
- instance->ConnectToClient(std::move(*params)); |
- return true; |
+ Instance* instance = GetExistingOrRootInstance((*params)->target()); |
+ if (instance) |
+ instance->ConnectToClient(std::move(*params)); |
+ return !!instance; |
} |
Shell::Instance* Shell::CreateInstance(const Identity& target_id, |
@@ -567,6 +588,8 @@ void Shell::OnGotResolvedName(scoped_ptr<ConnectParams> params, |
if (!base_filter.is_null()) |
filter = base_filter->filter.To<CapabilityFilter>(); |
+ mojom::ClientProcessConnectionPtr client_process_connection = |
+ params->TakeClientProcessConnection(); |
mojom::ShellClientRequest request; |
Instance* instance = CreateInstance(target, filter, &request); |
instance->ConnectToClient(std::move(params)); |
@@ -584,11 +607,15 @@ void Shell::OnGotResolvedName(scoped_ptr<ConnectParams> params, |
source, Identity(resolved_name, target.user_id(), instance_name), |
target.name(), std::move(request)); |
} else { |
- bool start_sandboxed = false; |
- native_runners_.push_back( |
- instance->StartWithFileURL(file_url.To<GURL>(), std::move(request), |
- start_sandboxed, |
- native_runner_factory_.get())); |
+ if (!client_process_connection.is_null()) { |
+ // The client already started a process for this instance, use it. |
+ instance->StartWithClientProcessConnection( |
+ std::move(request), std::move(client_process_connection)); |
+ } else { |
+ // Otherwise we make our own process. |
+ instance->StartWithFilePath(std::move(request), |
+ util::UrlToFilePath(file_url.To<GURL>())); |
+ } |
} |
} |