OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/user_cloud_policy_store.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "chrome/browser/policy/proto/cloud_policy.pb.h" | |
10 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
11 #include "chrome/browser/policy/proto/device_management_local.pb.h" | |
12 #include "chrome/browser/profiles/profile.h" | |
13 #include "chrome/browser/signin/signin_manager.h" | |
14 #include "chrome/browser/signin/signin_manager_factory.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "policy/policy_constants.h" | |
17 | |
18 namespace em = enterprise_management; | |
19 | |
20 namespace policy { | |
21 | |
22 enum PolicyLoadStatus { | |
23 // Policy blob was successfully loaded and parsed. | |
24 LOAD_RESULT_SUCCESS, | |
25 | |
26 // No previously stored policy was found. | |
27 LOAD_RESULT_NO_POLICY_FILE, | |
28 | |
29 // Could not load the previously stored policy due to either a parse or | |
30 // file read error. | |
31 LOAD_RESULT_LOAD_ERROR, | |
32 }; | |
33 | |
34 // Struct containing the result of a policy load - if |status| == | |
35 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. | |
36 struct PolicyLoadResult { | |
37 PolicyLoadStatus status; | |
38 em::PolicyFetchResponse policy; | |
39 }; | |
40 | |
41 namespace { | |
42 | |
43 // Subdirectory in the user's profile for storing user policies. | |
44 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); | |
45 // File in the above directory for storing user policy data. | |
46 const base::FilePath::CharType kPolicyCacheFile[] = | |
47 FILE_PATH_LITERAL("User Policy"); | |
48 | |
49 // Loads policy from the backing file. Returns a PolicyLoadResult with the | |
50 // results of the fetch. | |
51 policy::PolicyLoadResult LoadPolicyFromDisk(const base::FilePath& path) { | |
52 policy::PolicyLoadResult result; | |
53 // If the backing file does not exist, just return. | |
54 if (!file_util::PathExists(path)) { | |
55 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; | |
56 return result; | |
57 } | |
58 std::string data; | |
59 if (!file_util::ReadFileToString(path, &data) || | |
60 !result.policy.ParseFromArray(data.c_str(), data.size())) { | |
61 LOG(WARNING) << "Failed to read or parse policy data from " << path.value(); | |
62 result.status = policy::LOAD_RESULT_LOAD_ERROR; | |
63 return result; | |
64 } | |
65 | |
66 result.status = policy::LOAD_RESULT_SUCCESS; | |
67 return result; | |
68 } | |
69 | |
70 // Stores policy to the backing file (must be called via a task on | |
71 // the FILE thread). | |
72 void StorePolicyToDiskOnFileThread(const base::FilePath& path, | |
73 const em::PolicyFetchResponse& policy) { | |
74 DVLOG(1) << "Storing policy to " << path.value(); | |
75 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
76 std::string data; | |
77 if (!policy.SerializeToString(&data)) { | |
78 DLOG(WARNING) << "Failed to serialize policy data"; | |
79 return; | |
80 } | |
81 | |
82 if (!file_util::CreateDirectory(path.DirName())) { | |
83 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); | |
84 return; | |
85 } | |
86 | |
87 int size = data.size(); | |
88 if (file_util::WriteFile(path, data.c_str(), size) != size) { | |
89 DLOG(WARNING) << "Failed to write " << path.value(); | |
90 } | |
91 } | |
92 | |
93 } // namespace | |
94 | |
95 UserCloudPolicyStore::UserCloudPolicyStore(Profile* profile, | |
96 const base::FilePath& path) | |
97 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
98 profile_(profile), | |
99 backing_file_path_(path) { | |
100 } | |
101 | |
102 UserCloudPolicyStore::~UserCloudPolicyStore() {} | |
103 | |
104 // static | |
105 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( | |
106 Profile* profile) { | |
107 base::FilePath path = | |
108 profile->GetPath().Append(kPolicyDir).Append(kPolicyCacheFile); | |
109 return make_scoped_ptr(new UserCloudPolicyStore(profile, path)); | |
110 } | |
111 | |
112 void UserCloudPolicyStore::LoadImmediately() { | |
113 DVLOG(1) << "Initiating immediate policy load from disk"; | |
114 // Cancel any pending Load/Store/Validate operations. | |
115 weak_factory_.InvalidateWeakPtrs(); | |
116 // Load the policy from disk... | |
117 PolicyLoadResult result = LoadPolicyFromDisk(backing_file_path_); | |
118 // ...and install it, reporting success/failure to any observers. | |
119 PolicyLoaded(false, result); | |
120 } | |
121 | |
122 void UserCloudPolicyStore::Clear() { | |
123 content::BrowserThread::PostTask( | |
124 content::BrowserThread::FILE, FROM_HERE, | |
125 base::Bind(base::IgnoreResult(&file_util::Delete), | |
126 backing_file_path_, | |
127 false)); | |
128 policy_.reset(); | |
129 policy_map_.Clear(); | |
130 NotifyStoreLoaded(); | |
131 } | |
132 | |
133 void UserCloudPolicyStore::Load() { | |
134 DVLOG(1) << "Initiating policy load from disk"; | |
135 // Cancel any pending Load/Store/Validate operations. | |
136 weak_factory_.InvalidateWeakPtrs(); | |
137 | |
138 // Start a new Load operation and have us get called back when it is | |
139 // complete. | |
140 content::BrowserThread::PostTaskAndReplyWithResult( | |
141 content::BrowserThread::FILE, FROM_HERE, | |
142 base::Bind(&LoadPolicyFromDisk, backing_file_path_), | |
143 base::Bind(&UserCloudPolicyStore::PolicyLoaded, | |
144 weak_factory_.GetWeakPtr(), true)); | |
145 } | |
146 | |
147 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, | |
148 PolicyLoadResult result) { | |
149 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
150 switch (result.status) { | |
151 case LOAD_RESULT_LOAD_ERROR: | |
152 status_ = STATUS_LOAD_ERROR; | |
153 NotifyStoreError(); | |
154 break; | |
155 | |
156 case LOAD_RESULT_NO_POLICY_FILE: | |
157 DVLOG(1) << "No policy found on disk"; | |
158 NotifyStoreLoaded(); | |
159 break; | |
160 | |
161 case LOAD_RESULT_SUCCESS: { | |
162 // Found policy on disk - need to validate it before it can be used. | |
163 scoped_ptr<em::PolicyFetchResponse> cloud_policy( | |
164 new em::PolicyFetchResponse(result.policy)); | |
165 Validate(cloud_policy.Pass(), | |
166 validate_in_background, | |
167 base::Bind( | |
168 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, | |
169 weak_factory_.GetWeakPtr())); | |
170 break; | |
171 } | |
172 default: | |
173 NOTREACHED(); | |
174 } | |
175 } | |
176 | |
177 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( | |
178 UserCloudPolicyValidator* validator) { | |
179 validation_status_ = validator->status(); | |
180 if (!validator->success()) { | |
181 DVLOG(1) << "Validation failed: status=" << validation_status_; | |
182 status_ = STATUS_VALIDATION_ERROR; | |
183 NotifyStoreError(); | |
184 return; | |
185 } | |
186 | |
187 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << | |
188 validator->policy_data()->request_token(); | |
189 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); | |
190 | |
191 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | |
192 status_ = STATUS_OK; | |
193 NotifyStoreLoaded(); | |
194 } | |
195 | |
196 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { | |
197 // Stop any pending requests to store policy, then validate the new policy | |
198 // before storing it. | |
199 weak_factory_.InvalidateWeakPtrs(); | |
200 scoped_ptr<em::PolicyFetchResponse> policy_copy( | |
201 new em::PolicyFetchResponse(policy)); | |
202 Validate(policy_copy.Pass(), | |
203 true, | |
204 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, | |
205 weak_factory_.GetWeakPtr())); | |
206 } | |
207 | |
208 void UserCloudPolicyStore::Validate( | |
209 scoped_ptr<em::PolicyFetchResponse> policy, | |
210 bool validate_in_background, | |
211 const UserCloudPolicyValidator::CompletionCallback& callback) { | |
212 // Configure the validator. | |
213 scoped_ptr<UserCloudPolicyValidator> validator = | |
214 CreateValidator(policy.Pass()); | |
215 SigninManager* signin = SigninManagerFactory::GetForProfileIfExists(profile_); | |
216 if (signin) { | |
217 std::string username = signin->GetAuthenticatedUsername(); | |
218 // Validate the username if the user is signed in. | |
219 if (!username.empty()) | |
220 validator->ValidateUsername(username); | |
221 } | |
222 | |
223 if (validate_in_background) { | |
224 // Start validation in the background. The Validator will free itself once | |
225 // validation is complete. | |
226 validator.release()->StartValidation(callback); | |
227 } else { | |
228 // Run validation immediately and invoke the callback with the results. | |
229 validator->RunValidation(); | |
230 callback.Run(validator.get()); | |
231 } | |
232 } | |
233 | |
234 void UserCloudPolicyStore::StorePolicyAfterValidation( | |
235 UserCloudPolicyValidator* validator) { | |
236 validation_status_ = validator->status(); | |
237 DVLOG(1) << "Policy validation complete: status = " << validation_status_; | |
238 if (!validator->success()) { | |
239 status_ = STATUS_VALIDATION_ERROR; | |
240 NotifyStoreError(); | |
241 return; | |
242 } | |
243 | |
244 // Persist the validated policy (just fire a task - don't bother getting a | |
245 // reply because we can't do anything if it fails). | |
246 content::BrowserThread::PostTask( | |
247 content::BrowserThread::FILE, FROM_HERE, | |
248 base::Bind(&StorePolicyToDiskOnFileThread, | |
249 backing_file_path_, *validator->policy())); | |
250 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | |
251 status_ = STATUS_OK; | |
252 NotifyStoreLoaded(); | |
253 } | |
254 | |
255 } // namespace policy | |
OLD | NEW |