blob: c62f3f20bdd02cf067616e793e8fabe30b470b1f [file] [log] [blame]
Andreea Costinas942284d2020-01-28 16:28:40 +01001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4#include "system-proxy/system_proxy_adaptor.h"
5
6#include <string>
7#include <utility>
8#include <vector>
9
Qijiang Fan713061e2021-03-08 15:45:12 +090010#include <base/check.h>
11#include <base/check_op.h>
Andreea Costinas942284d2020-01-28 16:28:40 +010012#include <base/location.h>
Andreea Costinase9c73592020-07-17 15:27:54 +020013#include <base/strings/stringprintf.h>
Andreea Costinas91f75352020-07-08 14:47:47 +020014#include <base/time/time.h>
Andreea Costinas942284d2020-01-28 16:28:40 +010015#include <brillo/dbus/dbus_object.h>
Andreea Costinasc7d5ad02020-03-09 09:41:51 +010016#include <brillo/message_loops/message_loop.h>
Andreea Costinasedb7c8e2020-04-22 10:58:04 +020017#include <chromeos/dbus/service_constants.h>
Jason Jeremy Imanadffbcb2020-08-31 13:21:36 +090018#include <chromeos/patchpanel/dbus/client.h>
Andreea Costinasedb7c8e2020-04-22 10:58:04 +020019#include <dbus/object_proxy.h>
Andreea Costinas942284d2020-01-28 16:28:40 +010020
Andreea Costinas922fbaf2020-05-28 11:55:22 +020021#include "system-proxy/kerberos_client.h"
Andreea Costinasc7d5ad02020-03-09 09:41:51 +010022#include "system-proxy/sandboxed_worker.h"
Andreea Costinas942284d2020-01-28 16:28:40 +010023
24namespace system_proxy {
25namespace {
Andreea Costinasc7d5ad02020-03-09 09:41:51 +010026
Andreea Costinasedb7c8e2020-04-22 10:58:04 +020027constexpr int kProxyPort = 3128;
Andreea Costinas77b180e2020-05-12 15:17:32 +020028constexpr char kFailedToStartWorkerError[] = "Failed to start worker process";
Andreea Costinas91f75352020-07-08 14:47:47 +020029// Time delay for calling patchpanel::ConnectNamespace(). Patchpanel needs to
30// enter the network namespace of the worker process to configure it and fails
31// if it's soon after the process starts. See https://crbug.com/1095170 for
32// details.
33constexpr base::TimeDelta kConnectNamespaceDelay =
34 base::TimeDelta::FromSeconds(1);
35constexpr int kNetworkNamespaceReconnectAttempts = 3;
Andreea Costinasedb7c8e2020-04-22 10:58:04 +020036
Andreea Costinas942284d2020-01-28 16:28:40 +010037// Serializes |proto| to a vector of bytes.
38std::vector<uint8_t> SerializeProto(
39 const google::protobuf::MessageLite& proto) {
40 std::vector<uint8_t> proto_blob(proto.ByteSizeLong());
Andreea Costinasc991e232020-06-08 20:30:58 +020041 bool result = proto.SerializeToArray(proto_blob.data(), proto_blob.size());
42 DCHECK(result);
Andreea Costinas942284d2020-01-28 16:28:40 +010043 return proto_blob;
44}
45
46// Parses a proto from an array of bytes |proto_blob|. Returns
47// ERROR_PARSE_REQUEST_FAILED on error.
48std::string DeserializeProto(const base::Location& from_here,
49 google::protobuf::MessageLite* proto,
50 const std::vector<uint8_t>& proto_blob) {
51 if (!proto->ParseFromArray(proto_blob.data(), proto_blob.size())) {
52 const std::string error_message = "Failed to parse proto message.";
53 LOG(ERROR) << from_here.ToString() << error_message;
54 return error_message;
55 }
56 return "";
57}
58} // namespace
59
60SystemProxyAdaptor::SystemProxyAdaptor(
61 std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object)
62 : org::chromium::SystemProxyAdaptor(this),
Andreea Costinas91f75352020-07-08 14:47:47 +020063 netns_reconnect_attempts_available_(kNetworkNamespaceReconnectAttempts),
Andreea Costinasc7d5ad02020-03-09 09:41:51 +010064 dbus_object_(std::move(dbus_object)),
Andreea Costinas922fbaf2020-05-28 11:55:22 +020065 weak_ptr_factory_(this) {
66 kerberos_client_ = std::make_unique<KerberosClient>(dbus_object_->GetBus());
67}
Andreea Costinas942284d2020-01-28 16:28:40 +010068
69SystemProxyAdaptor::~SystemProxyAdaptor() = default;
70
71void SystemProxyAdaptor::RegisterAsync(
72 const brillo::dbus_utils::AsyncEventSequencer::CompletionAction&
73 completion_callback) {
74 RegisterWithDBusObject(dbus_object_.get());
75 dbus_object_->RegisterAsync(completion_callback);
76}
77
Andreea Costinas77b180e2020-05-12 15:17:32 +020078std::vector<uint8_t> SystemProxyAdaptor::SetAuthenticationDetails(
79 const std::vector<uint8_t>& request_blob) {
80 LOG(INFO) << "Received set authentication details request.";
81
82 SetAuthenticationDetailsRequest request;
Andreea Costinas350e4aa2020-07-20 20:29:46 +020083 std::string error_message =
Andreea Costinas77b180e2020-05-12 15:17:32 +020084 DeserializeProto(FROM_HERE, &request, request_blob);
85
86 SetAuthenticationDetailsResponse response;
87 if (!error_message.empty()) {
88 response.set_error_message(error_message);
89 return SerializeProto(response);
90 }
91
Andreea Costinas350e4aa2020-07-20 20:29:46 +020092 if (IncludesSystemTraffic(request.traffic_type())) {
93 SetAuthenticationDetails(request, /*user_traffic=*/false, &error_message);
94 }
95 if (IncludesUserTraffic(request.traffic_type())) {
96 SetAuthenticationDetails(request, /*user_traffic=*/true, &error_message);
97 }
98 if (!error_message.empty()) {
99 response.set_error_message(error_message);
100 }
101 return SerializeProto(response);
102}
103
104void SystemProxyAdaptor::SetAuthenticationDetails(
105 SetAuthenticationDetailsRequest auth_details,
106 bool user_traffic,
107 std::string* error_message) {
108 SandboxedWorker* worker = CreateWorkerIfNeeded(user_traffic);
109 if (!worker) {
110 error_message->append(kFailedToStartWorkerError);
111 return;
Andreea Costinas77b180e2020-05-12 15:17:32 +0200112 }
113
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200114 if (auth_details.has_credentials() || auth_details.has_protection_space()) {
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200115 worker::Credentials credentials;
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200116 if (auth_details.has_protection_space()) {
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200117 worker::ProtectionSpace protection_space;
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200118 protection_space.set_origin(auth_details.protection_space().origin());
119 protection_space.set_scheme(auth_details.protection_space().scheme());
120 protection_space.set_realm(auth_details.protection_space().realm());
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200121 *credentials.mutable_protection_space() = protection_space;
122 }
Andreea Costinas77b180e2020-05-12 15:17:32 +0200123
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200124 if (auth_details.has_credentials()) {
Andreea Costinascc4d54e2020-10-19 15:46:25 +0200125 system_proxy::Credentials dbus_cred = auth_details.credentials();
126 if (dbus_cred.has_username() && dbus_cred.has_password()) {
127 credentials.set_username(dbus_cred.username());
128 credentials.set_password(dbus_cred.password());
129 credentials.mutable_policy_credentials_auth_schemes()->Swap(
130 dbus_cred.mutable_policy_credentials_auth_schemes());
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200131 }
132 }
133
134 brillo::MessageLoop::current()->PostTask(
135 FROM_HERE,
136 base::Bind(&SystemProxyAdaptor::SetCredentialsTask,
137 weak_ptr_factory_.GetWeakPtr(), worker, credentials));
138 }
139 if (auth_details.has_kerberos_enabled()) {
140 std::string principal_name = auth_details.has_active_principal_name()
141 ? auth_details.active_principal_name()
Andreea Costinas922fbaf2020-05-28 11:55:22 +0200142 : std::string();
143
144 brillo::MessageLoop::current()->PostTask(
145 FROM_HERE, base::Bind(&SystemProxyAdaptor::SetKerberosEnabledTask,
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200146 weak_ptr_factory_.GetWeakPtr(), worker,
147 auth_details.kerberos_enabled(), principal_name));
Andreea Costinas922fbaf2020-05-28 11:55:22 +0200148 }
Andreea Costinas77b180e2020-05-12 15:17:32 +0200149}
150
Andreea Costinasfc3dc7d2020-07-20 18:54:38 +0200151// TODO(acostinas, crbug.com/1109144): Deprecated in favor of |ShutDownProcess|.
Andreea Costinas942284d2020-01-28 16:28:40 +0100152std::vector<uint8_t> SystemProxyAdaptor::ShutDown() {
153 LOG(INFO) << "Received shutdown request.";
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100154
155 std::string error_message;
Andreea Costinase9c73592020-07-17 15:27:54 +0200156 if (!ResetWorker(/* user_traffic=*/false)) {
157 error_message =
158 "Failure to terminate worker process for system services traffic.";
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100159 }
160
Andreea Costinase9c73592020-07-17 15:27:54 +0200161 if (!ResetWorker(/* user_traffic=*/true)) {
162 error_message += "Failure to terminate worker process for arc traffic.";
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100163 }
164
Andreea Costinas942284d2020-01-28 16:28:40 +0100165 ShutDownResponse response;
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100166 if (!error_message.empty())
167 response.set_error_message(error_message);
168
169 brillo::MessageLoop::current()->PostTask(
170 FROM_HERE, base::Bind(&SystemProxyAdaptor::ShutDownTask,
171 weak_ptr_factory_.GetWeakPtr()));
172
Andreea Costinas942284d2020-01-28 16:28:40 +0100173 return SerializeProto(response);
174}
175
Andreea Costinase9c73592020-07-17 15:27:54 +0200176std::vector<uint8_t> SystemProxyAdaptor::ClearUserCredentials(
177 const std::vector<uint8_t>& request_blob) {
178 LOG(INFO) << "Received request to clear user credentials.";
179 std::string error_message;
180 ClearUserCredentials(/*user_traffic=*/false, &error_message);
181 ClearUserCredentials(/*user_traffic=*/true, &error_message);
182
183 ClearUserCredentialsResponse response;
184 if (!error_message.empty())
185 response.set_error_message(error_message);
186 return SerializeProto(response);
187}
188
189void SystemProxyAdaptor::ClearUserCredentials(bool user_traffic,
190 std::string* error_message) {
191 SandboxedWorker* worker = GetWorker(user_traffic);
192 if (!worker) {
193 return;
194 }
195 if (!worker->ClearUserCredentials()) {
196 error_message->append(
197 base::StringPrintf("Failure to clear user credentials for worker with "
198 "pid %s. Restarting worker.",
199 std::to_string(worker->pid()).c_str()));
200 ResetWorker(user_traffic);
201 CreateWorkerIfNeeded(user_traffic);
202 }
203}
204
Andreea Costinasfc3dc7d2020-07-20 18:54:38 +0200205std::vector<uint8_t> SystemProxyAdaptor::ShutDownProcess(
206 const std::vector<uint8_t>& request_blob) {
207 LOG(INFO) << "Received shutdown request.";
208 ShutDownRequest request;
209 std::string error_message =
210 DeserializeProto(FROM_HERE, &request, request_blob);
211
212 if (IncludesSystemTraffic(request.traffic_type()) &&
213 !ResetWorker(/* user_traffic=*/false)) {
214 error_message =
215 "Failure to terminate worker process for system services traffic.";
216 }
217
218 if (IncludesUserTraffic(request.traffic_type()) &&
219 !ResetWorker(/* user_traffic=*/true)) {
220 error_message += "Failure to terminate worker process for arc traffic.";
221 }
222
223 ShutDownResponse response;
224 if (!error_message.empty())
225 response.set_error_message(error_message);
226
227 if (request.traffic_type() == TrafficOrigin::ALL) {
228 brillo::MessageLoop::current()->PostTask(
229 FROM_HERE, base::Bind(&SystemProxyAdaptor::ShutDownTask,
230 weak_ptr_factory_.GetWeakPtr()));
231 }
232 return SerializeProto(response);
233}
234
Andreea Costinas5862b102020-03-19 14:45:36 +0100235void SystemProxyAdaptor::GetChromeProxyServersAsync(
236 const std::string& target_url,
237 const brillo::http::GetChromeProxyServersCallback& callback) {
Andreea Costinasc9defae2020-04-22 10:28:35 +0200238 brillo::http::GetChromeProxyServersAsync(dbus_object_->GetBus(), target_url,
239 move(callback));
Andreea Costinas5862b102020-03-19 14:45:36 +0100240}
241
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200242bool SystemProxyAdaptor::IsLocalProxy(const std::string& proxy) {
243 if (system_services_worker_ &&
244 proxy.find(system_services_worker_->local_proxy_host_and_port()) !=
245 std::string::npos) {
246 return true;
247 }
248 return arc_worker_ && proxy.find(arc_worker_->local_proxy_host_and_port()) !=
249 std::string::npos;
250}
251
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100252std::unique_ptr<SandboxedWorker> SystemProxyAdaptor::CreateWorker() {
Andreea Costinas5862b102020-03-19 14:45:36 +0100253 return std::make_unique<SandboxedWorker>(weak_ptr_factory_.GetWeakPtr());
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100254}
255
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200256SandboxedWorker* SystemProxyAdaptor::CreateWorkerIfNeeded(bool user_traffic) {
257 SandboxedWorker* worker = GetWorker(user_traffic);
258 if (worker) {
259 // A worker for traffic indicated by |user_traffic| already exists.
260 return worker;
Andreea Costinas77b180e2020-05-12 15:17:32 +0200261 }
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200262 SetWorker(user_traffic, CreateWorker());
263 worker = GetWorker(user_traffic);
Andreea Costinas77b180e2020-05-12 15:17:32 +0200264
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200265 if (!worker->Start()) {
266 ResetWorker(user_traffic);
267 return nullptr;
Andreea Costinas77b180e2020-05-12 15:17:32 +0200268 }
269 // patchpanel_proxy is owned by |dbus_object_->bus_|.
270 dbus::ObjectProxy* patchpanel_proxy = dbus_object_->GetBus()->GetObjectProxy(
271 patchpanel::kPatchPanelServiceName,
272 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
273 patchpanel_proxy->WaitForServiceToBeAvailable(
274 base::Bind(&SystemProxyAdaptor::OnPatchpanelServiceAvailable,
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200275 weak_ptr_factory_.GetWeakPtr(), user_traffic));
276 return worker;
Andreea Costinas77b180e2020-05-12 15:17:32 +0200277}
278
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200279void SystemProxyAdaptor::SetCredentialsTask(
280 SandboxedWorker* worker, const worker::Credentials& credentials) {
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100281 DCHECK(worker);
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200282 worker->SetCredentials(credentials);
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100283}
284
Andreea Costinas922fbaf2020-05-28 11:55:22 +0200285void SystemProxyAdaptor::SetKerberosEnabledTask(
286 SandboxedWorker* worker,
287 bool kerberos_enabled,
288 const std::string& principal_name) {
289 DCHECK(worker);
Andreea Costinas922fbaf2020-05-28 11:55:22 +0200290 worker->SetKerberosEnabled(kerberos_enabled,
291 kerberos_client_->krb5_conf_path(),
292 kerberos_client_->krb5_ccache_path());
293 kerberos_client_->SetKerberosEnabled(kerberos_enabled);
294 if (kerberos_enabled) {
295 kerberos_client_->SetPrincipalName(principal_name);
296 }
297}
298
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100299void SystemProxyAdaptor::ShutDownTask() {
300 brillo::MessageLoop::current()->BreakLoop();
301}
302
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200303void SystemProxyAdaptor::SetWorker(bool user_traffic,
304 std::unique_ptr<SandboxedWorker> worker) {
305 if (user_traffic) {
306 arc_worker_ = std::move(worker);
307 } else {
308 system_services_worker_ = std::move(worker);
309 }
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100310}
311
Andreea Costinase9c73592020-07-17 15:27:54 +0200312bool SystemProxyAdaptor::ResetWorker(bool user_traffic) {
313 SandboxedWorker* worker =
314 user_traffic ? arc_worker_.get() : system_services_worker_.get();
315 if (!worker) {
316 return true;
317 }
318 if (!worker->Stop()) {
319 return false;
320 }
321 if (user_traffic) {
322 arc_worker_.reset();
323 } else {
324 system_services_worker_.reset();
325 }
326 return true;
327}
328
329SandboxedWorker* SystemProxyAdaptor::GetWorker(bool user_traffic) {
330 return user_traffic ? arc_worker_.get() : system_services_worker_.get();
331}
332
Andreea Costinasfc3dc7d2020-07-20 18:54:38 +0200333bool SystemProxyAdaptor::IncludesSystemTraffic(TrafficOrigin traffic_origin) {
334 return traffic_origin != TrafficOrigin::USER;
335}
336
337bool SystemProxyAdaptor::IncludesUserTraffic(TrafficOrigin traffic_origin) {
338 return traffic_origin != TrafficOrigin::SYSTEM;
339}
340
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200341void SystemProxyAdaptor::OnPatchpanelServiceAvailable(bool user_traffic,
342 bool is_available) {
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200343 if (!is_available) {
344 LOG(ERROR) << "Patchpanel service not available";
345 return;
346 }
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200347 ConnectNamespace(user_traffic);
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200348}
349
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200350void SystemProxyAdaptor::ConnectNamespace(bool user_traffic) {
Andreea Costinas91f75352020-07-08 14:47:47 +0200351 DCHECK_GT(netns_reconnect_attempts_available_, 0);
352 --netns_reconnect_attempts_available_;
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200353 SandboxedWorker* worker = GetWorker(user_traffic);
354 DCHECK(worker);
Andreea Costinas91f75352020-07-08 14:47:47 +0200355 // TODO(b/160736881, acostinas): Remove the delay after patchpanel
356 // implements "ip netns" to create the veth pair across network namespaces.
357 brillo::MessageLoop::current()->PostDelayedTask(
358 FROM_HERE,
359 base::Bind(&SystemProxyAdaptor::ConnectNamespaceTask,
Andreea Costinase9c73592020-07-17 15:27:54 +0200360 weak_ptr_factory_.GetWeakPtr(), worker, user_traffic),
Andreea Costinas91f75352020-07-08 14:47:47 +0200361 kConnectNamespaceDelay);
362}
363
364void SystemProxyAdaptor::ConnectNamespaceTask(SandboxedWorker* worker,
365 bool user_traffic) {
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200366 std::unique_ptr<patchpanel::Client> patchpanel_client =
367 patchpanel::Client::New();
368 if (!patchpanel_client) {
369 LOG(ERROR) << "Failed to open networking service client";
Andreea Costinas91f75352020-07-08 14:47:47 +0200370 return;
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200371 }
372
Garrick Evans58697022020-12-03 12:41:13 +0900373 // TODO(acostinas): The source will need to be updated to accommodate Crostini
374 // when proxy support is added.
375 auto traffic_source = user_traffic ? patchpanel::TrafficCounter::ARC
376 : patchpanel::TrafficCounter::SYSTEM;
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200377 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse> result =
378 patchpanel_client->ConnectNamespace(
Garrick Evans58697022020-12-03 12:41:13 +0900379 worker->pid(), "" /* outbound_ifname */, user_traffic,
380 true /* route_on_vpn */, traffic_source);
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200381
382 if (!result.first.is_valid()) {
Andreea Costinas91f75352020-07-08 14:47:47 +0200383 LOG(ERROR) << "Failed to setup network namespace on attempt "
384 << kNetworkNamespaceReconnectAttempts -
385 netns_reconnect_attempts_available_;
386 if (netns_reconnect_attempts_available_ > 0) {
Andreea Costinas350e4aa2020-07-20 20:29:46 +0200387 ConnectNamespace(user_traffic);
Andreea Costinas91f75352020-07-08 14:47:47 +0200388 }
389 return;
Andreea Costinasedb7c8e2020-04-22 10:58:04 +0200390 }
391
392 worker->SetNetNamespaceLifelineFd(std::move(result.first));
Garrick Evans20421132020-12-02 12:14:23 +0900393 if (!worker->SetListeningAddress(result.second.peer_ipv4_address(),
Andreea Costinasa89309d2020-05-08 15:51:12 +0200394 kProxyPort)) {
Andreea Costinas91f75352020-07-08 14:47:47 +0200395 return;
Andreea Costinasa89309d2020-05-08 15:51:12 +0200396 }
397 OnNamespaceConnected(worker, user_traffic);
Andreea Costinasa89309d2020-05-08 15:51:12 +0200398}
399
400void SystemProxyAdaptor::OnNamespaceConnected(SandboxedWorker* worker,
401 bool user_traffic) {
402 WorkerActiveSignalDetails details;
403 details.set_traffic_origin(user_traffic ? TrafficOrigin::USER
404 : TrafficOrigin::SYSTEM);
405 details.set_local_proxy_url(worker->local_proxy_host_and_port());
406 SendWorkerActiveSignal(SerializeProto(details));
Andreea Costinasc7d5ad02020-03-09 09:41:51 +0100407}
408
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200409void SystemProxyAdaptor::RequestAuthenticationCredentials(
Andreea Costinased9e6122020-08-12 12:06:19 +0200410 const worker::ProtectionSpace& protection_space,
411 bool bad_cached_credentials) {
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200412 AuthenticationRequiredDetails details;
413 ProtectionSpace proxy_protection_space;
414 proxy_protection_space.set_origin(protection_space.origin());
415 proxy_protection_space.set_realm(protection_space.realm());
416 proxy_protection_space.set_scheme(protection_space.scheme());
417 *details.mutable_proxy_protection_space() = proxy_protection_space;
Andreea Costinased9e6122020-08-12 12:06:19 +0200418 details.set_bad_cached_credentials(bad_cached_credentials);
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200419 SendAuthenticationRequiredSignal(SerializeProto(details));
420}
421
Andreea Costinas942284d2020-01-28 16:28:40 +0100422} // namespace system_proxy