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: 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 93 void URLQueryParameters::Put(const std::string& name, 94 const std::string& value) { 95 params_.push_back(std::make_pair(name, value)); 96 } 97 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: 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. 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 146 void SetQueryParam(const std::string& name, const std::string& value) { 147 query_params_.Put(name, value); 148 } 149 150 void SetAuthToken(const std::string& auth_token) { 151 auth_token_ = auth_token; 152 } 153 154 void SetDeviceManagementToken(const std::string& device_management_token) { 155 device_management_token_ = device_management_token; 156 } 157 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 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 258 GURL DeviceManagementJobBase::GetURL( 259 const std::string& server_url) { 260 return GURL(server_url + '?' + query_params_.Encode()); 261 } 262 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: 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 } 292 virtual ~DeviceManagementRegisterJob() {} 293 294 private: 295 // DeviceManagementJobBase overrides. 296 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 297 delegate_->OnError(error); 298 } 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: 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 } 327 virtual ~DeviceManagementUnregisterJob() {} 328 329 private: 330 // DeviceManagementJobBase overrides. 331 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 332 delegate_->OnError(error); 333 } 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: 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 } 362 virtual ~DeviceManagementPolicyJob() {} 363 364 private: 365 // DeviceManagementJobBase overrides. 366 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 367 delegate_->OnError(error); 368 } 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 378 DeviceManagementBackendImpl::DeviceManagementBackendImpl( 379 DeviceManagementService* service) 380 : service_(service) { 381 } 382 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 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 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 448 void DeviceManagementBackendImpl::JobDone(DeviceManagementJobBase* job) { 449 pending_jobs_.erase(job); 450 } 451 452 void DeviceManagementBackendImpl::AddJob(DeviceManagementJobBase* job) { 453 pending_jobs_.insert(job); 454 service_->AddJob(job); 455 } 456 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 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 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