1 // Copyright 2016 The Chromium 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 "chromeos/dbus/authpolicy/authpolicy_client.h"
5 
6 #include <utility>
7 
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "chromeos/dbus/authpolicy/fake_authpolicy_client.h"
15 #include "components/account_id/account_id.h"
16 #include "dbus/bus.h"
17 #include "dbus/message.h"
18 #include "dbus/object_proxy.h"
19 
20 namespace chromeos {
21 
22 namespace {
23 
24 // Policy fetch may take up to 300 seconds.  To ensure that a second policy
25 // fetch queuing after the first one can succeed (e.g. user policy following
26 // device policy), the D-Bus timeout needs to be at least twice that value.
27 // JoinADDomain() is an exception since it's always guaranteed to be the first
28 // call.
29 constexpr int kSlowDbusTimeoutMilliseconds = 630 * 1000;
30 
31 AuthPolicyClient* g_instance = nullptr;
32 
GetErrorFromReader(dbus::MessageReader * reader)33 authpolicy::ErrorType GetErrorFromReader(dbus::MessageReader* reader) {
34   int32_t int_error;
35   if (!reader->PopInt32(&int_error)) {
36     DLOG(ERROR) << "AuthPolicyClient: Failed to get an error from the response";
37     return authpolicy::ERROR_DBUS_FAILURE;
38   }
39   if (int_error < 0 || int_error >= authpolicy::ERROR_COUNT)
40     return authpolicy::ERROR_UNKNOWN;
41   return static_cast<authpolicy::ErrorType>(int_error);
42 }
43 
GetErrorAndProto(dbus::Response * response,google::protobuf::MessageLite * protobuf)44 authpolicy::ErrorType GetErrorAndProto(
45     dbus::Response* response,
46     google::protobuf::MessageLite* protobuf) {
47   if (!response) {
48     DLOG(ERROR) << "Auth: Failed to  call to authpolicy";
49     return authpolicy::ERROR_DBUS_FAILURE;
50   }
51   dbus::MessageReader reader(response);
52   const authpolicy::ErrorType error(GetErrorFromReader(&reader));
53 
54   if (error != authpolicy::ERROR_NONE)
55     return error;
56 
57   if (!reader.PopArrayOfBytesAsProto(protobuf)) {
58     DLOG(ERROR) << "Failed to parse protobuf.";
59     return authpolicy::ERROR_DBUS_FAILURE;
60   }
61   return authpolicy::ERROR_NONE;
62 }
63 
64 class AuthPolicyClientImpl : public AuthPolicyClient {
65  public:
AuthPolicyClientImpl()66   AuthPolicyClientImpl() {}
67 
68   ~AuthPolicyClientImpl() override = default;
69 
70   // AuthPolicyClient override.
JoinAdDomain(const authpolicy::JoinDomainRequest & request,int password_fd,JoinCallback callback)71   void JoinAdDomain(const authpolicy::JoinDomainRequest& request,
72                     int password_fd,
73                     JoinCallback callback) override {
74     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
75                                  authpolicy::kJoinADDomainMethod);
76     dbus::MessageWriter writer(&method_call);
77     if (!writer.AppendProtoAsArrayOfBytes(request)) {
78       base::ThreadTaskRunnerHandle::Get()->PostTask(
79           FROM_HERE,
80           base::BindOnce(std::move(callback), authpolicy::ERROR_DBUS_FAILURE,
81                          std::string()));
82       return;
83     }
84     writer.AppendFileDescriptor(password_fd);
85     proxy_->CallMethod(
86         &method_call, kSlowDbusTimeoutMilliseconds,
87         base::BindOnce(&AuthPolicyClientImpl::HandleJoinCallback,
88                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
89   }
90 
AuthenticateUser(const authpolicy::AuthenticateUserRequest & request,int password_fd,AuthCallback callback)91   void AuthenticateUser(const authpolicy::AuthenticateUserRequest& request,
92                         int password_fd,
93                         AuthCallback callback) override {
94     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
95                                  authpolicy::kAuthenticateUserMethod);
96     dbus::MessageWriter writer(&method_call);
97     if (!writer.AppendProtoAsArrayOfBytes(request)) {
98       base::ThreadTaskRunnerHandle::Get()->PostTask(
99           FROM_HERE,
100           base::BindOnce(std::move(callback), authpolicy::ERROR_DBUS_FAILURE,
101                          authpolicy::ActiveDirectoryAccountInfo()));
102       return;
103     }
104     writer.AppendFileDescriptor(password_fd);
105     proxy_->CallMethod(
106         &method_call, kSlowDbusTimeoutMilliseconds,
107         base::BindOnce(&AuthPolicyClientImpl::HandleCallback<
108                            authpolicy::ActiveDirectoryAccountInfo>,
109                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
110   }
111 
GetUserStatus(const authpolicy::GetUserStatusRequest & request,GetUserStatusCallback callback)112   void GetUserStatus(const authpolicy::GetUserStatusRequest& request,
113                      GetUserStatusCallback callback) override {
114     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
115                                  authpolicy::kGetUserStatusMethod);
116     dbus::MessageWriter writer(&method_call);
117     if (!writer.AppendProtoAsArrayOfBytes(request)) {
118       base::ThreadTaskRunnerHandle::Get()->PostTask(
119           FROM_HERE,
120           base::BindOnce(std::move(callback), authpolicy::ERROR_DBUS_FAILURE,
121                          authpolicy::ActiveDirectoryUserStatus()));
122       return;
123     }
124     proxy_->CallMethod(
125         &method_call, kSlowDbusTimeoutMilliseconds,
126         base::BindOnce(&AuthPolicyClientImpl::HandleCallback<
127                            authpolicy::ActiveDirectoryUserStatus>,
128                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
129   }
130 
GetUserKerberosFiles(const std::string & object_guid,GetUserKerberosFilesCallback callback)131   void GetUserKerberosFiles(const std::string& object_guid,
132                             GetUserKerberosFilesCallback callback) override {
133     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
134                                  authpolicy::kGetUserKerberosFilesMethod);
135     dbus::MessageWriter writer(&method_call);
136     writer.AppendString(object_guid);
137     proxy_->CallMethod(
138         &method_call, kSlowDbusTimeoutMilliseconds,
139         base::BindOnce(
140             &AuthPolicyClientImpl::HandleCallback<authpolicy::KerberosFiles>,
141             weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
142   }
143 
RefreshDevicePolicy(RefreshPolicyCallback callback)144   void RefreshDevicePolicy(RefreshPolicyCallback callback) override {
145     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
146                                  authpolicy::kRefreshDevicePolicyMethod);
147     proxy_->CallMethod(
148         &method_call, kSlowDbusTimeoutMilliseconds,
149         base::BindOnce(&AuthPolicyClientImpl::HandleRefreshPolicyCallback,
150                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
151   }
152 
RefreshUserPolicy(const AccountId & account_id,RefreshPolicyCallback callback)153   void RefreshUserPolicy(const AccountId& account_id,
154                          RefreshPolicyCallback callback) override {
155     DCHECK(account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY);
156     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
157                                  authpolicy::kRefreshUserPolicyMethod);
158     dbus::MessageWriter writer(&method_call);
159     writer.AppendString(account_id.GetObjGuid());
160     proxy_->CallMethod(
161         &method_call, kSlowDbusTimeoutMilliseconds,
162         base::BindOnce(&AuthPolicyClientImpl::HandleRefreshPolicyCallback,
163                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
164   }
165 
ConnectToSignal(const std::string & signal_name,dbus::ObjectProxy::SignalCallback signal_callback,dbus::ObjectProxy::OnConnectedCallback on_connected_callback)166   void ConnectToSignal(
167       const std::string& signal_name,
168       dbus::ObjectProxy::SignalCallback signal_callback,
169       dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
170     proxy_->ConnectToSignal(authpolicy::kAuthPolicyInterface, signal_name,
171                             std::move(signal_callback),
172                             std::move(on_connected_callback));
173   }
174 
WaitForServiceToBeAvailable(dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)175   void WaitForServiceToBeAvailable(
176       dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)
177       override {
178     proxy_->WaitForServiceToBeAvailable(std::move(callback));
179   }
180 
Init(dbus::Bus * bus)181   void Init(dbus::Bus* bus) {
182     bus_ = bus;
183     proxy_ = bus_->GetObjectProxy(
184         authpolicy::kAuthPolicyServiceName,
185         dbus::ObjectPath(authpolicy::kAuthPolicyServicePath));
186   }
187 
188  private:
HandleRefreshPolicyCallback(RefreshPolicyCallback callback,dbus::Response * response)189   void HandleRefreshPolicyCallback(RefreshPolicyCallback callback,
190                                    dbus::Response* response) {
191     if (!response) {
192       DLOG(ERROR) << "RefreshDevicePolicy: failed to call to authpolicy";
193       std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE);
194       return;
195     }
196     dbus::MessageReader reader(response);
197     std::move(callback).Run(GetErrorFromReader(&reader));
198   }
199 
HandleJoinCallback(JoinCallback callback,dbus::Response * response)200   void HandleJoinCallback(JoinCallback callback, dbus::Response* response) {
201     if (!response) {
202       DLOG(ERROR) << "Join: Couldn't call to authpolicy";
203       std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE, std::string());
204       return;
205     }
206 
207     dbus::MessageReader reader(response);
208     authpolicy::ErrorType error = GetErrorFromReader(&reader);
209     std::string machine_domain;
210     if (error == authpolicy::ERROR_NONE) {
211       if (!reader.PopString(&machine_domain))
212         error = authpolicy::ERROR_DBUS_FAILURE;
213     }
214     std::move(callback).Run(error, machine_domain);
215   }
216 
217   template <class T>
HandleCallback(base::OnceCallback<void (authpolicy::ErrorType error,const T & response)> callback,dbus::Response * response)218   void HandleCallback(base::OnceCallback<void(authpolicy::ErrorType error,
219                                               const T& response)> callback,
220                       dbus::Response* response) {
221     T proto;
222     authpolicy::ErrorType error(GetErrorAndProto(response, &proto));
223     std::move(callback).Run(error, proto);
224   }
225 
226   dbus::Bus* bus_ = nullptr;
227   dbus::ObjectProxy* proxy_ = nullptr;
228 
229   // Note: This should remain the last member so it'll be destroyed and
230   // invalidate its weak pointers before any other members are destroyed.
231   base::WeakPtrFactory<AuthPolicyClientImpl> weak_ptr_factory_{this};
232 
233   DISALLOW_COPY_AND_ASSIGN(AuthPolicyClientImpl);
234 };
235 
236 }  // namespace
237 
AuthPolicyClient()238 AuthPolicyClient::AuthPolicyClient() {
239   DCHECK(!g_instance);
240   g_instance = this;
241 }
242 
~AuthPolicyClient()243 AuthPolicyClient::~AuthPolicyClient() {
244   DCHECK_EQ(this, g_instance);
245   g_instance = nullptr;
246 }
247 
248 // static
Initialize(dbus::Bus * bus)249 void AuthPolicyClient::Initialize(dbus::Bus* bus) {
250   DCHECK(bus);
251   (new AuthPolicyClientImpl)->Init(bus);
252 }
253 
254 // static
InitializeFake()255 void AuthPolicyClient::InitializeFake() {
256   if (!FakeAuthPolicyClient::Get())
257     new FakeAuthPolicyClient();
258 }
259 
260 // static
Shutdown()261 void AuthPolicyClient::Shutdown() {
262   DCHECK(g_instance);
263   delete g_instance;
264 }
265 
266 // static
Get()267 AuthPolicyClient* AuthPolicyClient::Get() {
268   return g_instance;
269 }
270 
271 }  // namespace chromeos
272