OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #include "mojo/shell/shell.h" | 5 #include "mojo/shell/shell.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 if (source) { | 118 if (source) { |
119 interfaces = GetAllowedInterfaces(source->filter_, identity_); | 119 interfaces = GetAllowedInterfaces(source->filter_, identity_); |
120 source_id = source->id(); | 120 source_id = source->id(); |
121 } | 121 } |
122 shell_client_->AcceptConnection( | 122 shell_client_->AcceptConnection( |
123 mojom::Identity::From(params->source()), source_id, | 123 mojom::Identity::From(params->source()), source_id, |
124 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(), | 124 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(), |
125 Array<String>::From(interfaces), params->target().name()); | 125 Array<String>::From(interfaces), params->target().name()); |
126 } | 126 } |
127 | 127 |
128 scoped_ptr<NativeRunner> StartWithFileURL(const GURL& file_url, | 128 void StartWithClientProcessConnection( |
129 mojom::ShellClientRequest request, | 129 mojom::ShellClientRequest request, |
130 bool start_sandboxed, | 130 mojom::ClientProcessConnectionPtr client_process_connection) { |
131 NativeRunnerFactory* factory) { | 131 factory_.Bind(mojom::ShellClientFactoryPtrInfo( |
132 base::FilePath path = util::UrlToFilePath(file_url); | 132 std::move(client_process_connection->shell_client_factory), 0u)); |
133 scoped_ptr<NativeRunner> runner = factory->Create(path); | 133 pid_receiver_binding_.Bind( |
134 runner_ = runner.get(); | 134 std::move(client_process_connection->pid_receiver_request)); |
135 runner_->Start(path, identity_, start_sandboxed, std::move(request), | 135 factory_->CreateShellClient(std::move(request), identity_.name()); |
136 base::Bind(&Instance::PIDAvailable, | 136 } |
137 weak_factory_.GetWeakPtr()), | 137 |
138 base::Bind(&mojo::shell::Shell::CleanupRunner, | 138 void StartWithFilePath(mojom::ShellClientRequest request, |
139 shell_->weak_ptr_factory_.GetWeakPtr(), | 139 const base::FilePath& path) { |
140 runner_)); | 140 scoped_ptr<NativeRunner> runner = |
141 return runner; | 141 shell_->native_runner_factory_->Create(path); |
| 142 bool start_sandboxed = false; |
| 143 runner->Start(path, identity_, start_sandboxed, std::move(request), |
| 144 base::Bind(&Instance::PIDAvailable, |
| 145 weak_factory_.GetWeakPtr()), |
| 146 base::Bind(&mojo::shell::Shell::CleanupRunner, |
| 147 shell_->weak_ptr_factory_.GetWeakPtr(), |
| 148 runner.get())); |
| 149 shell_->native_runners_.push_back(std::move(runner)); |
142 } | 150 } |
143 | 151 |
144 mojom::InstanceInfoPtr CreateInstanceInfo() const { | 152 mojom::InstanceInfoPtr CreateInstanceInfo() const { |
145 mojom::InstanceInfoPtr info(mojom::InstanceInfo::New()); | 153 mojom::InstanceInfoPtr info(mojom::InstanceInfo::New()); |
146 info->id = id_; | 154 info->id = id_; |
147 info->identity = mojom::Identity::From(identity_); | 155 info->identity = mojom::Identity::From(identity_); |
148 info->pid = pid_; | 156 info->pid = pid_; |
149 return info; | 157 return info; |
150 } | 158 } |
151 | 159 |
152 const Identity& identity() const { return identity_; } | 160 const Identity& identity() const { return identity_; } |
153 uint32_t id() const { return id_; } | 161 uint32_t id() const { return id_; } |
154 | 162 |
155 // ShellClient: | 163 // ShellClient: |
156 bool AcceptConnection(Connection* connection) override { | 164 bool AcceptConnection(Connection* connection) override { |
157 connection->AddInterface<mojom::Shell>(this); | 165 connection->AddInterface<mojom::Shell>(this); |
158 return true; | 166 return true; |
159 } | 167 } |
160 | 168 |
161 private: | 169 private: |
162 // mojom::Connector implementation: | 170 // mojom::Connector implementation: |
163 void Connect(mojom::IdentityPtr target, | 171 void Connect(mojom::IdentityPtr target_ptr, |
164 mojom::InterfaceProviderRequest remote_interfaces, | 172 mojom::InterfaceProviderRequest remote_interfaces, |
165 mojom::InterfaceProviderPtr local_interfaces, | 173 mojom::InterfaceProviderPtr local_interfaces, |
| 174 mojom::ClientProcessConnectionPtr client_process_connection, |
166 const ConnectCallback& callback) override { | 175 const ConnectCallback& callback) override { |
167 if (!IsValidName(target->name)) { | 176 Identity target = target_ptr.To<Identity>(); |
168 LOG(ERROR) << "Error: invalid Name: " << target->name; | 177 if (!ValidateIdentity(target, callback)) |
169 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, | 178 return; |
170 mojom::kInheritUserID, mojom::kInvalidInstanceID); | 179 if (!ValidateClientProcessConnection(&client_process_connection, target, |
| 180 callback)) { |
171 return; | 181 return; |
172 } | 182 } |
173 if (!base::IsValidGUID(target->user_id)) { | 183 // TODO(beng): Need to do the following additional policy validation of |
174 LOG(ERROR) << "Error: invalid user_id: " << target->user_id; | 184 // whether this instance is allowed to connect using: |
175 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, | 185 // - a user id other than its own, kInheritUserID or kRootUserID. |
176 mojom::kInheritUserID, mojom::kInvalidInstanceID); | 186 // - a non-empty instance name. |
| 187 // - a non-null client_process_connection. |
| 188 if (!ValidateCapabilityFilter(target, callback)) |
177 return; | 189 return; |
178 } | 190 |
179 // TODO(beng): perform checking on policy of whether this instance is | 191 scoped_ptr<ConnectParams> params(new ConnectParams); |
180 // allowed to pass different user_ids. | 192 params->set_source(identity_); |
181 // TODO(beng): perform checking on policy of whether this instance is | 193 params->set_target(target); |
182 // allowed to pass non-empty instance identifiers. | 194 params->set_remote_interfaces(std::move(remote_interfaces)); |
183 if (allow_any_application_ || filter_.find(target->name) != filter_.end()) { | 195 params->set_local_interfaces(std::move(local_interfaces)); |
184 scoped_ptr<ConnectParams> params(new ConnectParams); | 196 params->set_client_process_connection(std::move(client_process_connection)); |
185 params->set_source(identity_); | 197 params->set_connect_callback(callback); |
186 params->set_target(target.To<Identity>()); | 198 shell_->Connect(std::move(params)); |
187 params->set_remote_interfaces(std::move(remote_interfaces)); | |
188 params->set_local_interfaces(std::move(local_interfaces)); | |
189 params->set_connect_callback(callback); | |
190 shell_->Connect(std::move(params)); | |
191 } else { | |
192 LOG(WARNING) << "CapabilityFilter prevented connection from: " << | |
193 identity_.name() << " to: " << target->name; | |
194 callback.Run(mojom::ConnectResult::ACCESS_DENIED, | |
195 mojom::kInheritUserID, mojom::kInvalidInstanceID); | |
196 } | |
197 } | 199 } |
198 void Clone(mojom::ConnectorRequest request) override { | 200 void Clone(mojom::ConnectorRequest request) override { |
199 connectors_.AddBinding(this, std::move(request)); | 201 connectors_.AddBinding(this, std::move(request)); |
200 } | 202 } |
201 | 203 |
202 // mojom::PIDReceiver: | 204 // mojom::PIDReceiver: |
203 void SetPID(uint32_t pid) override { | 205 void SetPID(uint32_t pid) override { |
204 PIDAvailable(pid); | 206 PIDAvailable(pid); |
205 } | 207 } |
206 | 208 |
207 // InterfaceFactory<mojom::Shell>: | 209 // InterfaceFactory<mojom::Shell>: |
208 void Create(Connection* connection, | 210 void Create(Connection* connection, |
209 mojom::ShellRequest request) override { | 211 mojom::ShellRequest request) override { |
210 shell_bindings_.AddBinding(this, std::move(request)); | 212 shell_bindings_.AddBinding(this, std::move(request)); |
211 } | 213 } |
212 | 214 |
213 // mojom::Shell implementation: | 215 // mojom::Shell implementation: |
214 void CreateInstance(mojom::ShellClientFactoryPtr factory, | |
215 mojom::IdentityPtr target, | |
216 mojom::PIDReceiverRequest pid_receiver, | |
217 const CreateInstanceCallback& callback) override { | |
218 // We need to bounce through the package manager to load the | |
219 // CapabilityFilter. | |
220 std::string name = target->name; | |
221 shell_->shell_resolver_->ResolveMojoName(name, base::Bind( | |
222 &mojo::shell::Shell::Instance::OnResolvedNameForCreateInstance, | |
223 weak_factory_.GetWeakPtr(), base::Passed(std::move(factory)), | |
224 base::Passed(std::move(target)), base::Passed(std::move(pid_receiver)), | |
225 callback)); | |
226 } | |
227 void AddInstanceListener(mojom::InstanceListenerPtr listener) override { | 216 void AddInstanceListener(mojom::InstanceListenerPtr listener) override { |
228 // TODO(beng): this should only track the instances matching this user, and | 217 // TODO(beng): this should only track the instances matching this user, and |
229 // root. | 218 // root. |
230 shell_->AddInstanceListener(std::move(listener)); | 219 shell_->AddInstanceListener(std::move(listener)); |
231 } | 220 } |
232 | 221 |
233 void OnResolvedNameForCreateInstance(mojom::ShellClientFactoryPtr factory, | 222 bool ValidateIdentity(const Identity& identity, |
234 mojom::IdentityPtr target, | 223 const ConnectCallback& callback) { |
235 mojom::PIDReceiverRequest pid_receiver, | 224 if (!IsValidName(identity.name())) { |
236 const CreateInstanceCallback& callback, | 225 LOG(ERROR) << "Error: invalid Name: " << identity.name(); |
237 const String& resolved_name, | 226 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
238 const String& resolved_instance, | 227 mojom::kInheritUserID, mojom::kInvalidInstanceID); |
239 mojom::CapabilityFilterPtr filter, | 228 return false; |
240 const String& file_url) { | 229 } |
241 if (!base::IsValidGUID(target->user_id)) | 230 if (!base::IsValidGUID(identity.user_id())) { |
242 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT); | 231 LOG(ERROR) << "Error: invalid user_id: " << identity.user_id(); |
| 232 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
| 233 mojom::kInheritUserID, mojom::kInvalidInstanceID); |
| 234 return false; |
| 235 } |
| 236 return true; |
| 237 } |
243 | 238 |
244 Identity target_id = target.To<Identity>(); | 239 bool ValidateClientProcessConnection( |
| 240 mojom::ClientProcessConnectionPtr* client_process_connection, |
| 241 const Identity& identity, |
| 242 const ConnectCallback& callback) { |
| 243 if (!client_process_connection->is_null()) { |
| 244 if (!(*client_process_connection)->shell_client_factory.is_valid() || |
| 245 !(*client_process_connection)->pid_receiver_request.is_valid()) { |
| 246 LOG(ERROR) << "Error: must supply both shell_client_factory AND " |
| 247 << "pid_receiver_request when sending " |
| 248 << "client_process_connection."; |
| 249 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
| 250 mojom::kInheritUserID, mojom::kInvalidInstanceID); |
| 251 return false; |
| 252 } |
| 253 if (shell_->GetExistingOrRootInstance(identity)) { |
| 254 LOG(ERROR) << "Error: Cannot client process matching existing identity:" |
| 255 << "Name: " << identity.name() << " User: " |
| 256 << identity.user_id() << " Instance: " |
| 257 << identity.instance(); |
| 258 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
| 259 mojom::kInheritUserID, mojom::kInvalidInstanceID); |
| 260 return false; |
| 261 } |
| 262 } |
| 263 return true; |
| 264 } |
245 | 265 |
246 // TODO(beng): perform checking on policy of whether this instance is | 266 bool ValidateCapabilityFilter(const Identity& target, |
247 // allowed to pass different user_ids. | 267 const ConnectCallback& callback) { |
248 if (target_id.user_id() == mojom::kInheritUserID) | 268 if (allow_any_application_ || |
249 target_id.set_user_id(identity_.user_id()); | 269 filter_.find(target.name()) != filter_.end()) { |
250 | 270 return true; |
251 mojom::ShellClientRequest request; | 271 } |
252 Instance* instance = shell_->CreateInstance( | 272 LOG(ERROR) << "CapabilityFilter prevented connection from: " << |
253 target_id, filter->filter.To<CapabilityFilter>(), &request); | 273 identity_.name() << " to: " << target.name(); |
254 instance->pid_receiver_binding_.Bind(std::move(pid_receiver)); | 274 callback.Run(mojom::ConnectResult::ACCESS_DENIED, |
255 instance->factory_ = std::move(factory); | 275 mojom::kInheritUserID, mojom::kInvalidInstanceID); |
256 instance->factory_->CreateShellClient(std::move(request), target->name); | 276 return false; |
257 callback.Run(mojom::ConnectResult::SUCCEEDED); | |
258 // We don't call ConnectToClient() here since the instance was created | |
259 // manually by other code, not in response to a Connect() request. The newly | |
260 // created instance is identified by |name| and may be subsequently reached | |
261 // by client code using this identity. | |
262 } | 277 } |
263 | 278 |
264 uint32_t GenerateUniqueID() const { | 279 uint32_t GenerateUniqueID() const { |
265 static uint32_t id = mojom::kInvalidInstanceID; | 280 static uint32_t id = mojom::kInvalidInstanceID; |
266 ++id; | 281 ++id; |
267 CHECK_NE(mojom::kInvalidInstanceID, id); | 282 CHECK_NE(mojom::kInvalidInstanceID, id); |
268 return id; | 283 return id; |
269 } | 284 } |
270 | 285 |
271 void PIDAvailable(base::ProcessId pid) { | 286 void PIDAvailable(base::ProcessId pid) { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 }); | 464 }); |
450 if (!instance_quit_callback_.is_null()) | 465 if (!instance_quit_callback_.is_null()) |
451 instance_quit_callback_.Run(identity); | 466 instance_quit_callback_.Run(identity); |
452 } | 467 } |
453 | 468 |
454 Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const { | 469 Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const { |
455 const auto& it = identity_to_instance_.find(identity); | 470 const auto& it = identity_to_instance_.find(identity); |
456 return it != identity_to_instance_.end() ? it->second : nullptr; | 471 return it != identity_to_instance_.end() ? it->second : nullptr; |
457 } | 472 } |
458 | 473 |
| 474 Shell::Instance* Shell::GetExistingOrRootInstance( |
| 475 const Identity& identity) const { |
| 476 Instance* instance = GetExistingInstance(identity); |
| 477 if (!instance) { |
| 478 Identity root_identity = identity; |
| 479 root_identity.set_user_id(mojom::kRootUserID); |
| 480 instance = GetExistingInstance(root_identity); |
| 481 } |
| 482 return instance; |
| 483 } |
| 484 |
459 void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) { | 485 void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) { |
460 instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) { | 486 instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) { |
461 listener->InstancePIDAvailable(id, pid); | 487 listener->InstancePIDAvailable(id, pid); |
462 }); | 488 }); |
463 } | 489 } |
464 | 490 |
465 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { | 491 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { |
466 Instance* instance = GetExistingInstance((*params)->target()); | 492 Instance* instance = GetExistingOrRootInstance((*params)->target()); |
467 if (!instance) { | 493 if (instance) |
468 Identity root_identity = (*params)->target(); | 494 instance->ConnectToClient(std::move(*params)); |
469 root_identity.set_user_id(mojom::kRootUserID); | 495 return !!instance; |
470 instance = GetExistingInstance(root_identity); | |
471 if (!instance) return false; | |
472 } | |
473 instance->ConnectToClient(std::move(*params)); | |
474 return true; | |
475 } | 496 } |
476 | 497 |
477 Shell::Instance* Shell::CreateInstance(const Identity& target_id, | 498 Shell::Instance* Shell::CreateInstance(const Identity& target_id, |
478 const CapabilityFilter& filter, | 499 const CapabilityFilter& filter, |
479 mojom::ShellClientRequest* request) { | 500 mojom::ShellClientRequest* request) { |
480 CHECK(target_id.user_id() != mojom::kInheritUserID); | 501 CHECK(target_id.user_id() != mojom::kInheritUserID); |
481 mojom::ShellClientPtr shell_client; | 502 mojom::ShellClientPtr shell_client; |
482 *request = GetProxy(&shell_client); | 503 *request = GetProxy(&shell_client); |
483 Instance* instance = | 504 Instance* instance = |
484 new Instance(std::move(shell_client), this, target_id, filter); | 505 new Instance(std::move(shell_client), this, target_id, filter); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 if (ConnectToExistingInstance(¶ms)) | 581 if (ConnectToExistingInstance(¶ms)) |
561 return; | 582 return; |
562 | 583 |
563 Identity source = params->source(); | 584 Identity source = params->source(); |
564 // |base_filter| can be null when there is no manifest, e.g. for URL types | 585 // |base_filter| can be null when there is no manifest, e.g. for URL types |
565 // not resolvable by the resolver. | 586 // not resolvable by the resolver. |
566 CapabilityFilter filter = GetPermissiveCapabilityFilter(); | 587 CapabilityFilter filter = GetPermissiveCapabilityFilter(); |
567 if (!base_filter.is_null()) | 588 if (!base_filter.is_null()) |
568 filter = base_filter->filter.To<CapabilityFilter>(); | 589 filter = base_filter->filter.To<CapabilityFilter>(); |
569 | 590 |
| 591 mojom::ClientProcessConnectionPtr client_process_connection = |
| 592 params->TakeClientProcessConnection(); |
570 mojom::ShellClientRequest request; | 593 mojom::ShellClientRequest request; |
571 Instance* instance = CreateInstance(target, filter, &request); | 594 Instance* instance = CreateInstance(target, filter, &request); |
572 instance->ConnectToClient(std::move(params)); | 595 instance->ConnectToClient(std::move(params)); |
573 | 596 |
574 if (LoadWithLoader(target, &request)) | 597 if (LoadWithLoader(target, &request)) |
575 return; | 598 return; |
576 | 599 |
577 CHECK(!file_url.is_null() && !base_filter.is_null()); | 600 CHECK(!file_url.is_null() && !base_filter.is_null()); |
578 | 601 |
579 if (target.name() != resolved_name) { | 602 if (target.name() != resolved_name) { |
580 // In cases where a package alias is resolved, we have to use the instance | 603 // In cases where a package alias is resolved, we have to use the instance |
581 // from the original request rather than for the package itself, which will | 604 // from the original request rather than for the package itself, which will |
582 // always be the same. | 605 // always be the same. |
583 CreateShellClient( | 606 CreateShellClient( |
584 source, Identity(resolved_name, target.user_id(), instance_name), | 607 source, Identity(resolved_name, target.user_id(), instance_name), |
585 target.name(), std::move(request)); | 608 target.name(), std::move(request)); |
586 } else { | 609 } else { |
587 bool start_sandboxed = false; | 610 if (!client_process_connection.is_null()) { |
588 native_runners_.push_back( | 611 // The client already started a process for this instance, use it. |
589 instance->StartWithFileURL(file_url.To<GURL>(), std::move(request), | 612 instance->StartWithClientProcessConnection( |
590 start_sandboxed, | 613 std::move(request), std::move(client_process_connection)); |
591 native_runner_factory_.get())); | 614 } else { |
| 615 // Otherwise we make our own process. |
| 616 instance->StartWithFilePath(std::move(request), |
| 617 util::UrlToFilePath(file_url.To<GURL>())); |
| 618 } |
592 } | 619 } |
593 } | 620 } |
594 | 621 |
595 bool Shell::LoadWithLoader(const Identity& target, | 622 bool Shell::LoadWithLoader(const Identity& target, |
596 mojom::ShellClientRequest* request) { | 623 mojom::ShellClientRequest* request) { |
597 Loader* loader = GetLoaderForName(target.name()); | 624 Loader* loader = GetLoaderForName(target.name()); |
598 if (!loader) | 625 if (!loader) |
599 return false; | 626 return false; |
600 loader->Load(target.name(), std::move(*request)); | 627 loader->Load(target.name(), std::move(*request)); |
601 return true; | 628 return true; |
(...skipping 10 matching lines...) Expand all Loading... |
612 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { | 639 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { |
613 if (it->get() == runner) { | 640 if (it->get() == runner) { |
614 native_runners_.erase(it); | 641 native_runners_.erase(it); |
615 return; | 642 return; |
616 } | 643 } |
617 } | 644 } |
618 } | 645 } |
619 | 646 |
620 } // namespace shell | 647 } // namespace shell |
621 } // namespace mojo | 648 } // namespace mojo |
OLD | NEW |