• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
6 
7 #include <string>
8 
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/callback_helpers.h"
13 #include "base/logging.h"
14 #include "base/strings/stringize_macros.h"
15 #include "base/threading/thread.h"
16 #include "base/values.h"
17 #include "google_apis/gaia/gaia_oauth_client.h"
18 #include "google_apis/google_api_keys.h"
19 #include "net/base/net_util.h"
20 #include "remoting/base/rsa_key_pair.h"
21 #include "remoting/host/pin_hash.h"
22 #include "remoting/host/setup/oauth_client.h"
23 #include "remoting/protocol/pairing_registry.h"
24 
25 namespace {
26 
27 // redirect_uri to use when authenticating service accounts (service account
28 // codes are obtained "out-of-band", i.e., not through an OAuth redirect).
29 const char* kServiceAccountRedirectUri = "oob";
30 
31 // Features supported in addition to the base protocol.
32 const char* kSupportedFeatures[] = {
33   "pairingRegistry",
34   "oauthClient"
35 };
36 
37 // Helper to extract the "config" part of a message as a DictionaryValue.
38 // Returns NULL on failure, and logs an error message.
ConfigDictionaryFromMessage(const base::DictionaryValue & message)39 scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
40     const base::DictionaryValue& message) {
41   scoped_ptr<base::DictionaryValue> result;
42   const base::DictionaryValue* config_dict;
43   if (message.GetDictionary("config", &config_dict)) {
44     result.reset(config_dict->DeepCopy());
45   } else {
46     LOG(ERROR) << "'config' dictionary not found";
47   }
48   return result.Pass();
49 }
50 
51 }  // namespace
52 
53 namespace remoting {
54 
Me2MeNativeMessagingHost(scoped_ptr<NativeMessagingChannel> channel,scoped_refptr<DaemonController> daemon_controller,scoped_refptr<protocol::PairingRegistry> pairing_registry,scoped_ptr<OAuthClient> oauth_client)55 Me2MeNativeMessagingHost::Me2MeNativeMessagingHost(
56     scoped_ptr<NativeMessagingChannel> channel,
57     scoped_refptr<DaemonController> daemon_controller,
58     scoped_refptr<protocol::PairingRegistry> pairing_registry,
59     scoped_ptr<OAuthClient> oauth_client)
60     : channel_(channel.Pass()),
61       daemon_controller_(daemon_controller),
62       pairing_registry_(pairing_registry),
63       oauth_client_(oauth_client.Pass()),
64       weak_factory_(this) {
65   weak_ptr_ = weak_factory_.GetWeakPtr();
66 }
67 
~Me2MeNativeMessagingHost()68 Me2MeNativeMessagingHost::~Me2MeNativeMessagingHost() {
69   DCHECK(thread_checker_.CalledOnValidThread());
70 }
71 
Start(const base::Closure & quit_closure)72 void Me2MeNativeMessagingHost::Start(
73       const base::Closure& quit_closure) {
74   DCHECK(thread_checker_.CalledOnValidThread());
75 
76   channel_->Start(
77       base::Bind(&Me2MeNativeMessagingHost::ProcessMessage, weak_ptr_),
78       quit_closure);
79 }
80 
ProcessMessage(scoped_ptr<base::DictionaryValue> message)81 void Me2MeNativeMessagingHost::ProcessMessage(
82     scoped_ptr<base::DictionaryValue> message) {
83   DCHECK(thread_checker_.CalledOnValidThread());
84 
85   scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
86 
87   // If the client supplies an ID, it will expect it in the response. This
88   // might be a string or a number, so cope with both.
89   const base::Value* id;
90   if (message->Get("id", &id))
91     response->Set("id", id->DeepCopy());
92 
93   std::string type;
94   if (!message->GetString("type", &type)) {
95     LOG(ERROR) << "'type' not found";
96     channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
97     return;
98   }
99 
100   response->SetString("type", type + "Response");
101 
102   bool success = false;
103   if (type == "hello") {
104     success = ProcessHello(*message, response.Pass());
105   } else if (type == "clearPairedClients") {
106     success = ProcessClearPairedClients(*message, response.Pass());
107   } else if (type == "deletePairedClient") {
108     success = ProcessDeletePairedClient(*message, response.Pass());
109   } else if (type == "getHostName") {
110     success = ProcessGetHostName(*message, response.Pass());
111   } else if (type == "getPinHash") {
112     success = ProcessGetPinHash(*message, response.Pass());
113   } else if (type == "generateKeyPair") {
114     success = ProcessGenerateKeyPair(*message, response.Pass());
115   } else if (type == "updateDaemonConfig") {
116     success = ProcessUpdateDaemonConfig(*message, response.Pass());
117   } else if (type == "getDaemonConfig") {
118     success = ProcessGetDaemonConfig(*message, response.Pass());
119   } else if (type == "getPairedClients") {
120     success = ProcessGetPairedClients(*message, response.Pass());
121   } else if (type == "getUsageStatsConsent") {
122     success = ProcessGetUsageStatsConsent(*message, response.Pass());
123   } else if (type == "startDaemon") {
124     success = ProcessStartDaemon(*message, response.Pass());
125   } else if (type == "stopDaemon") {
126     success = ProcessStopDaemon(*message, response.Pass());
127   } else if (type == "getDaemonState") {
128     success = ProcessGetDaemonState(*message, response.Pass());
129   } else if (type == "getHostClientId") {
130     success = ProcessGetHostClientId(*message, response.Pass());
131   } else if (type == "getCredentialsFromAuthCode") {
132     success = ProcessGetCredentialsFromAuthCode(*message, response.Pass());
133   } else {
134     LOG(ERROR) << "Unsupported request type: " << type;
135   }
136 
137   if (!success)
138     channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
139 }
140 
ProcessHello(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)141 bool Me2MeNativeMessagingHost::ProcessHello(
142     const base::DictionaryValue& message,
143     scoped_ptr<base::DictionaryValue> response) {
144   DCHECK(thread_checker_.CalledOnValidThread());
145 
146   response->SetString("version", STRINGIZE(VERSION));
147   scoped_ptr<base::ListValue> supported_features_list(new base::ListValue());
148   supported_features_list->AppendStrings(std::vector<std::string>(
149       kSupportedFeatures, kSupportedFeatures + arraysize(kSupportedFeatures)));
150   response->Set("supportedFeatures", supported_features_list.release());
151   channel_->SendMessage(response.Pass());
152   return true;
153 }
154 
ProcessClearPairedClients(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)155 bool Me2MeNativeMessagingHost::ProcessClearPairedClients(
156     const base::DictionaryValue& message,
157     scoped_ptr<base::DictionaryValue> response) {
158   DCHECK(thread_checker_.CalledOnValidThread());
159 
160   if (pairing_registry_) {
161     pairing_registry_->ClearAllPairings(
162         base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
163                    base::Passed(&response)));
164   } else {
165     SendBooleanResult(response.Pass(), false);
166   }
167   return true;
168 }
169 
ProcessDeletePairedClient(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)170 bool Me2MeNativeMessagingHost::ProcessDeletePairedClient(
171     const base::DictionaryValue& message,
172     scoped_ptr<base::DictionaryValue> response) {
173   DCHECK(thread_checker_.CalledOnValidThread());
174 
175   std::string client_id;
176   if (!message.GetString(protocol::PairingRegistry::kClientIdKey, &client_id)) {
177     LOG(ERROR) << "'" << protocol::PairingRegistry::kClientIdKey
178                << "' string not found.";
179     return false;
180   }
181 
182   if (pairing_registry_) {
183     pairing_registry_->DeletePairing(
184         client_id, base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult,
185                               weak_ptr_, base::Passed(&response)));
186   } else {
187     SendBooleanResult(response.Pass(), false);
188   }
189   return true;
190 }
191 
ProcessGetHostName(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)192 bool Me2MeNativeMessagingHost::ProcessGetHostName(
193     const base::DictionaryValue& message,
194     scoped_ptr<base::DictionaryValue> response) {
195   DCHECK(thread_checker_.CalledOnValidThread());
196 
197   response->SetString("hostname", net::GetHostName());
198   channel_->SendMessage(response.Pass());
199   return true;
200 }
201 
ProcessGetPinHash(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)202 bool Me2MeNativeMessagingHost::ProcessGetPinHash(
203     const base::DictionaryValue& message,
204     scoped_ptr<base::DictionaryValue> response) {
205   DCHECK(thread_checker_.CalledOnValidThread());
206 
207   std::string host_id;
208   if (!message.GetString("hostId", &host_id)) {
209     LOG(ERROR) << "'hostId' not found: " << message;
210     return false;
211   }
212   std::string pin;
213   if (!message.GetString("pin", &pin)) {
214     LOG(ERROR) << "'pin' not found: " << message;
215     return false;
216   }
217   response->SetString("hash", MakeHostPinHash(host_id, pin));
218   channel_->SendMessage(response.Pass());
219   return true;
220 }
221 
ProcessGenerateKeyPair(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)222 bool Me2MeNativeMessagingHost::ProcessGenerateKeyPair(
223     const base::DictionaryValue& message,
224     scoped_ptr<base::DictionaryValue> response) {
225   DCHECK(thread_checker_.CalledOnValidThread());
226 
227   scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
228   response->SetString("privateKey", key_pair->ToString());
229   response->SetString("publicKey", key_pair->GetPublicKey());
230   channel_->SendMessage(response.Pass());
231   return true;
232 }
233 
ProcessUpdateDaemonConfig(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)234 bool Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig(
235     const base::DictionaryValue& message,
236     scoped_ptr<base::DictionaryValue> response) {
237   DCHECK(thread_checker_.CalledOnValidThread());
238 
239   scoped_ptr<base::DictionaryValue> config_dict =
240       ConfigDictionaryFromMessage(message);
241   if (!config_dict)
242     return false;
243 
244   daemon_controller_->UpdateConfig(
245       config_dict.Pass(),
246       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
247                  base::Passed(&response)));
248   return true;
249 }
250 
ProcessGetDaemonConfig(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)251 bool Me2MeNativeMessagingHost::ProcessGetDaemonConfig(
252     const base::DictionaryValue& message,
253     scoped_ptr<base::DictionaryValue> response) {
254   DCHECK(thread_checker_.CalledOnValidThread());
255 
256   daemon_controller_->GetConfig(
257       base::Bind(&Me2MeNativeMessagingHost::SendConfigResponse, weak_ptr_,
258                  base::Passed(&response)));
259   return true;
260 }
261 
ProcessGetPairedClients(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)262 bool Me2MeNativeMessagingHost::ProcessGetPairedClients(
263     const base::DictionaryValue& message,
264     scoped_ptr<base::DictionaryValue> response) {
265   DCHECK(thread_checker_.CalledOnValidThread());
266 
267   if (pairing_registry_) {
268     pairing_registry_->GetAllPairings(
269         base::Bind(&Me2MeNativeMessagingHost::SendPairedClientsResponse,
270                    weak_ptr_, base::Passed(&response)));
271   } else {
272     scoped_ptr<base::ListValue> no_paired_clients(new base::ListValue);
273     SendPairedClientsResponse(response.Pass(), no_paired_clients.Pass());
274   }
275   return true;
276 }
277 
ProcessGetUsageStatsConsent(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)278 bool Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent(
279     const base::DictionaryValue& message,
280     scoped_ptr<base::DictionaryValue> response) {
281   DCHECK(thread_checker_.CalledOnValidThread());
282 
283   daemon_controller_->GetUsageStatsConsent(
284       base::Bind(&Me2MeNativeMessagingHost::SendUsageStatsConsentResponse,
285                  weak_ptr_, base::Passed(&response)));
286   return true;
287 }
288 
ProcessStartDaemon(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)289 bool Me2MeNativeMessagingHost::ProcessStartDaemon(
290     const base::DictionaryValue& message,
291     scoped_ptr<base::DictionaryValue> response) {
292   DCHECK(thread_checker_.CalledOnValidThread());
293 
294   bool consent;
295   if (!message.GetBoolean("consent", &consent)) {
296     LOG(ERROR) << "'consent' not found.";
297     return false;
298   }
299 
300   scoped_ptr<base::DictionaryValue> config_dict =
301       ConfigDictionaryFromMessage(message);
302   if (!config_dict)
303     return false;
304 
305   daemon_controller_->SetConfigAndStart(
306       config_dict.Pass(), consent,
307       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
308                  base::Passed(&response)));
309   return true;
310 }
311 
ProcessStopDaemon(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)312 bool Me2MeNativeMessagingHost::ProcessStopDaemon(
313     const base::DictionaryValue& message,
314     scoped_ptr<base::DictionaryValue> response) {
315   DCHECK(thread_checker_.CalledOnValidThread());
316 
317   daemon_controller_->Stop(
318       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
319                  base::Passed(&response)));
320   return true;
321 }
322 
ProcessGetDaemonState(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)323 bool Me2MeNativeMessagingHost::ProcessGetDaemonState(
324     const base::DictionaryValue& message,
325     scoped_ptr<base::DictionaryValue> response) {
326   DCHECK(thread_checker_.CalledOnValidThread());
327 
328   DaemonController::State state = daemon_controller_->GetState();
329   switch (state) {
330     case DaemonController::STATE_NOT_IMPLEMENTED:
331       response->SetString("state", "NOT_IMPLEMENTED");
332       break;
333     case DaemonController::STATE_NOT_INSTALLED:
334       response->SetString("state", "NOT_INSTALLED");
335       break;
336     case DaemonController::STATE_INSTALLING:
337       response->SetString("state", "INSTALLING");
338       break;
339     case DaemonController::STATE_STOPPED:
340       response->SetString("state", "STOPPED");
341       break;
342     case DaemonController::STATE_STARTING:
343       response->SetString("state", "STARTING");
344       break;
345     case DaemonController::STATE_STARTED:
346       response->SetString("state", "STARTED");
347       break;
348     case DaemonController::STATE_STOPPING:
349       response->SetString("state", "STOPPING");
350       break;
351     case DaemonController::STATE_UNKNOWN:
352       response->SetString("state", "UNKNOWN");
353       break;
354   }
355   channel_->SendMessage(response.Pass());
356   return true;
357 }
358 
ProcessGetHostClientId(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)359 bool Me2MeNativeMessagingHost::ProcessGetHostClientId(
360     const base::DictionaryValue& message,
361     scoped_ptr<base::DictionaryValue> response) {
362   DCHECK(thread_checker_.CalledOnValidThread());
363 
364   response->SetString("clientId", google_apis::GetOAuth2ClientID(
365       google_apis::CLIENT_REMOTING_HOST));
366   channel_->SendMessage(response.Pass());
367   return true;
368 }
369 
ProcessGetCredentialsFromAuthCode(const base::DictionaryValue & message,scoped_ptr<base::DictionaryValue> response)370 bool Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode(
371     const base::DictionaryValue& message,
372     scoped_ptr<base::DictionaryValue> response) {
373   DCHECK(thread_checker_.CalledOnValidThread());
374 
375   std::string auth_code;
376   if (!message.GetString("authorizationCode", &auth_code)) {
377     LOG(ERROR) << "'authorizationCode' string not found.";
378     return false;
379   }
380 
381   gaia::OAuthClientInfo oauth_client_info = {
382     google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
383     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
384     kServiceAccountRedirectUri
385   };
386 
387   oauth_client_->GetCredentialsFromAuthCode(
388       oauth_client_info, auth_code, base::Bind(
389           &Me2MeNativeMessagingHost::SendCredentialsResponse, weak_ptr_,
390           base::Passed(&response)));
391 
392   return true;
393 }
394 
SendConfigResponse(scoped_ptr<base::DictionaryValue> response,scoped_ptr<base::DictionaryValue> config)395 void Me2MeNativeMessagingHost::SendConfigResponse(
396     scoped_ptr<base::DictionaryValue> response,
397     scoped_ptr<base::DictionaryValue> config) {
398   DCHECK(thread_checker_.CalledOnValidThread());
399 
400   if (config) {
401     response->Set("config", config.release());
402   } else {
403     response->Set("config", Value::CreateNullValue());
404   }
405   channel_->SendMessage(response.Pass());
406 }
407 
SendPairedClientsResponse(scoped_ptr<base::DictionaryValue> response,scoped_ptr<base::ListValue> pairings)408 void Me2MeNativeMessagingHost::SendPairedClientsResponse(
409     scoped_ptr<base::DictionaryValue> response,
410     scoped_ptr<base::ListValue> pairings) {
411   DCHECK(thread_checker_.CalledOnValidThread());
412 
413   response->Set("pairedClients", pairings.release());
414   channel_->SendMessage(response.Pass());
415 }
416 
SendUsageStatsConsentResponse(scoped_ptr<base::DictionaryValue> response,const DaemonController::UsageStatsConsent & consent)417 void Me2MeNativeMessagingHost::SendUsageStatsConsentResponse(
418     scoped_ptr<base::DictionaryValue> response,
419     const DaemonController::UsageStatsConsent& consent) {
420   DCHECK(thread_checker_.CalledOnValidThread());
421 
422   response->SetBoolean("supported", consent.supported);
423   response->SetBoolean("allowed", consent.allowed);
424   response->SetBoolean("setByPolicy", consent.set_by_policy);
425   channel_->SendMessage(response.Pass());
426 }
427 
SendAsyncResult(scoped_ptr<base::DictionaryValue> response,DaemonController::AsyncResult result)428 void Me2MeNativeMessagingHost::SendAsyncResult(
429     scoped_ptr<base::DictionaryValue> response,
430     DaemonController::AsyncResult result) {
431   DCHECK(thread_checker_.CalledOnValidThread());
432 
433   switch (result) {
434     case DaemonController::RESULT_OK:
435       response->SetString("result", "OK");
436       break;
437     case DaemonController::RESULT_FAILED:
438       response->SetString("result", "FAILED");
439       break;
440     case DaemonController::RESULT_CANCELLED:
441       response->SetString("result", "CANCELLED");
442       break;
443     case DaemonController::RESULT_FAILED_DIRECTORY:
444       response->SetString("result", "FAILED_DIRECTORY");
445       break;
446   }
447   channel_->SendMessage(response.Pass());
448 }
449 
SendBooleanResult(scoped_ptr<base::DictionaryValue> response,bool result)450 void Me2MeNativeMessagingHost::SendBooleanResult(
451     scoped_ptr<base::DictionaryValue> response, bool result) {
452   DCHECK(thread_checker_.CalledOnValidThread());
453 
454   response->SetBoolean("result", result);
455   channel_->SendMessage(response.Pass());
456 }
457 
SendCredentialsResponse(scoped_ptr<base::DictionaryValue> response,const std::string & user_email,const std::string & refresh_token)458 void Me2MeNativeMessagingHost::SendCredentialsResponse(
459     scoped_ptr<base::DictionaryValue> response,
460     const std::string& user_email,
461     const std::string& refresh_token) {
462   DCHECK(thread_checker_.CalledOnValidThread());
463 
464   response->SetString("userEmail", user_email);
465   response->SetString("refreshToken", refresh_token);
466   channel_->SendMessage(response.Pass());
467 }
468 
469 }  // namespace remoting
470