• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/policy/device_management_backend_impl.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #if defined(OS_POSIX) && !defined(OS_MACOSX)
11 #include <sys/utsname.h>
12 #endif
13 
14 #include "base/stringprintf.h"
15 #include "base/sys_info.h"
16 #include "chrome/browser/policy/device_management_service.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "net/base/escape.h"
19 #include "net/url_request/url_request_status.h"
20 
21 #if defined(OS_CHROMEOS)
22 #include "chrome/browser/chromeos/system_access.h"
23 #endif
24 
25 namespace policy {
26 
27 // Name constants for URL query parameters.
28 const char DeviceManagementBackendImpl::kParamRequest[] = "request";
29 const char DeviceManagementBackendImpl::kParamDeviceType[] = "devicetype";
30 const char DeviceManagementBackendImpl::kParamAppType[] = "apptype";
31 const char DeviceManagementBackendImpl::kParamDeviceID[] = "deviceid";
32 const char DeviceManagementBackendImpl::kParamAgent[] = "agent";
33 const char DeviceManagementBackendImpl::kParamPlatform[] = "platform";
34 
35 // String constants for the device and app type we report to the server.
36 const char DeviceManagementBackendImpl::kValueRequestRegister[] = "register";
37 const char DeviceManagementBackendImpl::kValueRequestUnregister[] =
38     "unregister";
39 const char DeviceManagementBackendImpl::kValueRequestPolicy[] = "policy";
40 const char DeviceManagementBackendImpl::kValueDeviceType[] = "2";
41 const char DeviceManagementBackendImpl::kValueAppType[] = "Chrome";
42 
43 namespace {
44 
45 const char kValueAgent[] = "%s %s(%s)";
46 const char kValuePlatform[] = "%s|%s|%s";
47 
48 const char kPostContentType[] = "application/protobuf";
49 
50 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
51 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
52 
53 // HTTP Error Codes of the DM Server with their concrete meinings in the context
54 // of the DM Server communication.
55 const int kSuccess = 200;
56 const int kInvalidArgument = 400;
57 const int kInvalidAuthCookieOrDMToken = 401;
58 const int kDeviceManagementNotAllowed = 403;
59 const int kInvalidURL = 404; // This error is not coming from the GFE.
60 const int kPendingApproval = 491;
61 const int kInternalServerError = 500;
62 const int kServiceUnavailable = 503;
63 const int kDeviceNotFound = 901;
64 const int kPolicyNotFound = 902; // This error is not sent as HTTP status code.
65 
66 #if defined(OS_CHROMEOS)
67 // Machine info keys.
68 const char kMachineInfoHWClass[] = "hardware_class";
69 const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD";
70 #endif
71 
72 }  // namespace
73 
74 // Helper class for URL query parameter encoding/decoding.
75 class URLQueryParameters {
76  public:
URLQueryParameters()77   URLQueryParameters() {}
78 
79   // Add a query parameter.
80   void Put(const std::string& name, const std::string& value);
81 
82   // Produce the query string, taking care of properly encoding and assembling
83   // the names and values.
84   std::string Encode();
85 
86  private:
87   typedef std::vector<std::pair<std::string, std::string> > ParameterMap;
88   ParameterMap params_;
89 
90   DISALLOW_COPY_AND_ASSIGN(URLQueryParameters);
91 };
92 
Put(const std::string & name,const std::string & value)93 void URLQueryParameters::Put(const std::string& name,
94                              const std::string& value) {
95   params_.push_back(std::make_pair(name, value));
96 }
97 
Encode()98 std::string URLQueryParameters::Encode() {
99   std::string result;
100   for (ParameterMap::const_iterator entry(params_.begin());
101        entry != params_.end();
102        ++entry) {
103     if (entry != params_.begin())
104       result += '&';
105     result += EscapeQueryParamValue(entry->first, true);
106     result += '=';
107     result += EscapeQueryParamValue(entry->second, true);
108   }
109   return result;
110 }
111 
112 // A base class containing the common code for the jobs created by the backend
113 // implementation. Subclasses provide custom code for handling actual register,
114 // unregister, and policy jobs.
115 class DeviceManagementJobBase
116     : public DeviceManagementService::DeviceManagementJob {
117  public:
~DeviceManagementJobBase()118   virtual ~DeviceManagementJobBase() {}
119 
120   // DeviceManagementJob overrides:
121   virtual void HandleResponse(const net::URLRequestStatus& status,
122                               int response_code,
123                               const ResponseCookies& cookies,
124                               const std::string& data);
125   virtual GURL GetURL(const std::string& server_url);
126   virtual void ConfigureRequest(URLFetcher* fetcher);
127 
128  protected:
129   // Constructs a device management job running for the given backend.
DeviceManagementJobBase(DeviceManagementBackendImpl * backend_impl,const std::string & request_type,const std::string & device_id)130   DeviceManagementJobBase(DeviceManagementBackendImpl* backend_impl,
131                           const std::string& request_type,
132                           const std::string& device_id)
133       : backend_impl_(backend_impl) {
134     query_params_.Put(DeviceManagementBackendImpl::kParamRequest, request_type);
135     query_params_.Put(DeviceManagementBackendImpl::kParamDeviceType,
136                       DeviceManagementBackendImpl::kValueDeviceType);
137     query_params_.Put(DeviceManagementBackendImpl::kParamAppType,
138                       DeviceManagementBackendImpl::kValueAppType);
139     query_params_.Put(DeviceManagementBackendImpl::kParamDeviceID, device_id);
140     query_params_.Put(DeviceManagementBackendImpl::kParamAgent,
141                       DeviceManagementBackendImpl::GetAgentString());
142     query_params_.Put(DeviceManagementBackendImpl::kParamPlatform,
143                       DeviceManagementBackendImpl::GetPlatformString());
144   }
145 
SetQueryParam(const std::string & name,const std::string & value)146   void SetQueryParam(const std::string& name, const std::string& value) {
147     query_params_.Put(name, value);
148   }
149 
SetAuthToken(const std::string & auth_token)150   void SetAuthToken(const std::string& auth_token) {
151     auth_token_ = auth_token;
152   }
153 
SetDeviceManagementToken(const std::string & device_management_token)154   void SetDeviceManagementToken(const std::string& device_management_token) {
155     device_management_token_ = device_management_token;
156   }
157 
SetPayload(const em::DeviceManagementRequest & request)158   void SetPayload(const em::DeviceManagementRequest& request) {
159     if (!request.SerializeToString(&payload_)) {
160       NOTREACHED();
161       LOG(ERROR) << "Failed to serialize request.";
162     }
163   }
164 
165  private:
166   // Implemented by subclasses to handle decoded responses and errors.
167   virtual void OnResponse(
168       const em::DeviceManagementResponse& response) = 0;
169   virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0;
170 
171   // The backend this job is handling a request for.
172   DeviceManagementBackendImpl* backend_impl_;
173 
174   // Query parameters.
175   URLQueryParameters query_params_;
176 
177   // Auth token (if applicaple).
178   std::string auth_token_;
179 
180   // Device management token (if applicable).
181   std::string device_management_token_;
182 
183   // The payload.
184   std::string payload_;
185 
186   DISALLOW_COPY_AND_ASSIGN(DeviceManagementJobBase);
187 };
188 
HandleResponse(const net::URLRequestStatus & status,int response_code,const ResponseCookies & cookies,const std::string & data)189 void DeviceManagementJobBase::HandleResponse(
190     const net::URLRequestStatus& status,
191     int response_code,
192     const ResponseCookies& cookies,
193     const std::string& data) {
194   // Delete ourselves when this is done.
195   scoped_ptr<DeviceManagementJob> scoped_killer(this);
196   backend_impl_->JobDone(this);
197   backend_impl_ = NULL;
198 
199   if (status.status() != net::URLRequestStatus::SUCCESS) {
200     OnError(DeviceManagementBackend::kErrorRequestFailed);
201     return;
202   }
203 
204   switch (response_code) {
205     case kSuccess: {
206       em::DeviceManagementResponse response;
207       if (!response.ParseFromString(data)) {
208         OnError(DeviceManagementBackend::kErrorResponseDecoding);
209         return;
210       }
211       OnResponse(response);
212       return;
213     }
214     case kInvalidArgument: {
215       OnError(DeviceManagementBackend::kErrorRequestInvalid);
216       return;
217     }
218     case kInvalidAuthCookieOrDMToken: {
219       OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid);
220       return;
221     }
222     case kDeviceManagementNotAllowed: {
223       OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported);
224       return;
225     }
226     case kPendingApproval: {
227       OnError(DeviceManagementBackend::kErrorServiceActivationPending);
228       return;
229     }
230     case kInvalidURL:
231     case kInternalServerError:
232     case kServiceUnavailable: {
233       OnError(DeviceManagementBackend::kErrorTemporaryUnavailable);
234       return;
235     }
236     case kDeviceNotFound: {
237       OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound);
238       return;
239     }
240     case kPolicyNotFound: {
241       OnError(DeviceManagementBackend::kErrorServicePolicyNotFound);
242       break;
243     }
244     default: {
245       VLOG(1) << "Unexpected HTTP status in response from DMServer : "
246               << response_code << ".";
247       // Handle all unknown 5xx HTTP error codes as temporary and any other
248       // unknown error as one that needs more time to recover.
249       if (response_code >= 500 && response_code <= 599)
250         OnError(DeviceManagementBackend::kErrorTemporaryUnavailable);
251       else
252         OnError(DeviceManagementBackend::kErrorHttpStatus);
253       return;
254     }
255   }
256 }
257 
GetURL(const std::string & server_url)258 GURL DeviceManagementJobBase::GetURL(
259     const std::string& server_url) {
260   return GURL(server_url + '?' + query_params_.Encode());
261 }
262 
ConfigureRequest(URLFetcher * fetcher)263 void DeviceManagementJobBase::ConfigureRequest(URLFetcher* fetcher) {
264   fetcher->set_upload_data(kPostContentType, payload_);
265   std::string extra_headers;
266   if (!auth_token_.empty())
267     extra_headers += kServiceTokenAuthHeader + auth_token_ + "\n";
268   if (!device_management_token_.empty())
269     extra_headers += kDMTokenAuthHeader + device_management_token_ + "\n";
270   fetcher->set_extra_request_headers(extra_headers);
271 }
272 
273 // Handles device registration jobs.
274 class DeviceManagementRegisterJob : public DeviceManagementJobBase {
275  public:
DeviceManagementRegisterJob(DeviceManagementBackendImpl * backend_impl,const std::string & auth_token,const std::string & device_id,const em::DeviceRegisterRequest & request,DeviceManagementBackend::DeviceRegisterResponseDelegate * delegate)276   DeviceManagementRegisterJob(
277       DeviceManagementBackendImpl* backend_impl,
278       const std::string& auth_token,
279       const std::string& device_id,
280       const em::DeviceRegisterRequest& request,
281       DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate)
282       : DeviceManagementJobBase(
283           backend_impl,
284           DeviceManagementBackendImpl::kValueRequestRegister,
285           device_id),
286         delegate_(delegate) {
287     SetAuthToken(auth_token);
288     em::DeviceManagementRequest request_wrapper;
289     request_wrapper.mutable_register_request()->CopyFrom(request);
290     SetPayload(request_wrapper);
291   }
~DeviceManagementRegisterJob()292   virtual ~DeviceManagementRegisterJob() {}
293 
294  private:
295   // DeviceManagementJobBase overrides.
OnError(DeviceManagementBackend::ErrorCode error)296   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
297     delegate_->OnError(error);
298   }
OnResponse(const em::DeviceManagementResponse & response)299   virtual void OnResponse(const em::DeviceManagementResponse& response) {
300     delegate_->HandleRegisterResponse(response.register_response());
301   }
302 
303   DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_;
304 
305   DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob);
306 };
307 
308 // Handles device unregistration jobs.
309 class DeviceManagementUnregisterJob : public DeviceManagementJobBase {
310  public:
DeviceManagementUnregisterJob(DeviceManagementBackendImpl * backend_impl,const std::string & device_management_token,const std::string & device_id,const em::DeviceUnregisterRequest & request,DeviceManagementBackend::DeviceUnregisterResponseDelegate * delegate)311   DeviceManagementUnregisterJob(
312       DeviceManagementBackendImpl* backend_impl,
313       const std::string& device_management_token,
314       const std::string& device_id,
315       const em::DeviceUnregisterRequest& request,
316       DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate)
317       : DeviceManagementJobBase(
318           backend_impl,
319           DeviceManagementBackendImpl::kValueRequestUnregister,
320           device_id),
321         delegate_(delegate) {
322     SetDeviceManagementToken(device_management_token);
323     em::DeviceManagementRequest request_wrapper;
324     request_wrapper.mutable_unregister_request()->CopyFrom(request);
325     SetPayload(request_wrapper);
326   }
~DeviceManagementUnregisterJob()327   virtual ~DeviceManagementUnregisterJob() {}
328 
329  private:
330   // DeviceManagementJobBase overrides.
OnError(DeviceManagementBackend::ErrorCode error)331   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
332     delegate_->OnError(error);
333   }
OnResponse(const em::DeviceManagementResponse & response)334   virtual void OnResponse(const em::DeviceManagementResponse& response) {
335     delegate_->HandleUnregisterResponse(response.unregister_response());
336   }
337 
338   DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_;
339 
340   DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob);
341 };
342 
343 // Handles policy request jobs.
344 class DeviceManagementPolicyJob : public DeviceManagementJobBase {
345  public:
DeviceManagementPolicyJob(DeviceManagementBackendImpl * backend_impl,const std::string & device_management_token,const std::string & device_id,const em::DevicePolicyRequest & request,DeviceManagementBackend::DevicePolicyResponseDelegate * delegate)346   DeviceManagementPolicyJob(
347       DeviceManagementBackendImpl* backend_impl,
348       const std::string& device_management_token,
349       const std::string& device_id,
350       const em::DevicePolicyRequest& request,
351       DeviceManagementBackend::DevicePolicyResponseDelegate* delegate)
352       : DeviceManagementJobBase(
353           backend_impl,
354           DeviceManagementBackendImpl::kValueRequestPolicy,
355           device_id),
356         delegate_(delegate) {
357     SetDeviceManagementToken(device_management_token);
358     em::DeviceManagementRequest request_wrapper;
359     request_wrapper.mutable_policy_request()->CopyFrom(request);
360     SetPayload(request_wrapper);
361   }
~DeviceManagementPolicyJob()362   virtual ~DeviceManagementPolicyJob() {}
363 
364  private:
365   // DeviceManagementJobBase overrides.
OnError(DeviceManagementBackend::ErrorCode error)366   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
367     delegate_->OnError(error);
368   }
OnResponse(const em::DeviceManagementResponse & response)369   virtual void OnResponse(const em::DeviceManagementResponse& response) {
370     delegate_->HandlePolicyResponse(response.policy_response());
371   }
372 
373   DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_;
374 
375   DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob);
376 };
377 
DeviceManagementBackendImpl(DeviceManagementService * service)378 DeviceManagementBackendImpl::DeviceManagementBackendImpl(
379     DeviceManagementService* service)
380     : service_(service) {
381 }
382 
~DeviceManagementBackendImpl()383 DeviceManagementBackendImpl::~DeviceManagementBackendImpl() {
384   for (JobSet::iterator job(pending_jobs_.begin());
385        job != pending_jobs_.end();
386        ++job) {
387     service_->RemoveJob(*job);
388     delete *job;
389   }
390   pending_jobs_.clear();
391 }
392 
GetAgentString()393 std::string DeviceManagementBackendImpl::GetAgentString() {
394   static std::string agent;
395   if (!agent.empty())
396     return agent;
397 
398   chrome::VersionInfo version_info;
399   agent = base::StringPrintf(kValueAgent,
400                              version_info.Name().c_str(),
401                              version_info.Version().c_str(),
402                              version_info.LastChange().c_str());
403   return agent;
404 }
405 
GetPlatformString()406 std::string DeviceManagementBackendImpl::GetPlatformString() {
407   static std::string platform;
408   if (!platform.empty())
409     return platform;
410 
411   std::string os_name(base::SysInfo::OperatingSystemName());
412   std::string os_hardware(base::SysInfo::CPUArchitecture());
413 
414 #if defined(OS_CHROMEOS)
415   chromeos::SystemAccess* sys_lib = chromeos::SystemAccess::GetInstance();
416 
417   std::string hwclass;
418   std::string board;
419   if (!sys_lib->GetMachineStatistic(kMachineInfoHWClass, &hwclass) ||
420       !sys_lib->GetMachineStatistic(kMachineInfoBoard, &board)) {
421     LOG(ERROR) << "Failed to get machine information";
422   }
423   os_name += ",CrOS," + board;
424   os_hardware += "," + hwclass;
425 #endif
426 
427   std::string os_version("-");
428 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
429   int32 os_major_version = 0;
430   int32 os_minor_version = 0;
431   int32 os_bugfix_version = 0;
432   base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
433                                                &os_minor_version,
434                                                &os_bugfix_version);
435   os_version = base::StringPrintf("%d.%d.%d",
436                                   os_major_version,
437                                   os_minor_version,
438                                   os_bugfix_version);
439 #endif
440 
441   platform = base::StringPrintf(kValuePlatform,
442                                 os_name.c_str(),
443                                 os_hardware.c_str(),
444                                 os_version.c_str());
445   return platform;
446 }
447 
JobDone(DeviceManagementJobBase * job)448 void DeviceManagementBackendImpl::JobDone(DeviceManagementJobBase* job) {
449   pending_jobs_.erase(job);
450 }
451 
AddJob(DeviceManagementJobBase * job)452 void DeviceManagementBackendImpl::AddJob(DeviceManagementJobBase* job) {
453   pending_jobs_.insert(job);
454   service_->AddJob(job);
455 }
456 
ProcessRegisterRequest(const std::string & auth_token,const std::string & device_id,const em::DeviceRegisterRequest & request,DeviceRegisterResponseDelegate * delegate)457 void DeviceManagementBackendImpl::ProcessRegisterRequest(
458     const std::string& auth_token,
459     const std::string& device_id,
460     const em::DeviceRegisterRequest& request,
461     DeviceRegisterResponseDelegate* delegate) {
462   AddJob(new DeviceManagementRegisterJob(this, auth_token, device_id, request,
463                                          delegate));
464 }
465 
ProcessUnregisterRequest(const std::string & device_management_token,const std::string & device_id,const em::DeviceUnregisterRequest & request,DeviceUnregisterResponseDelegate * delegate)466 void DeviceManagementBackendImpl::ProcessUnregisterRequest(
467     const std::string& device_management_token,
468     const std::string& device_id,
469     const em::DeviceUnregisterRequest& request,
470     DeviceUnregisterResponseDelegate* delegate) {
471   AddJob(new DeviceManagementUnregisterJob(this, device_management_token,
472                                            device_id, request, delegate));
473 }
474 
ProcessPolicyRequest(const std::string & device_management_token,const std::string & device_id,const em::DevicePolicyRequest & request,DevicePolicyResponseDelegate * delegate)475 void DeviceManagementBackendImpl::ProcessPolicyRequest(
476     const std::string& device_management_token,
477     const std::string& device_id,
478     const em::DevicePolicyRequest& request,
479     DevicePolicyResponseDelegate* delegate) {
480   AddJob(new DeviceManagementPolicyJob(this, device_management_token, device_id,
481                                        request, delegate));
482 }
483 
484 }  // namespace policy
485