Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / system_log_uploader.cc
blob2dbc739fcf582b297dbf34d676ef192e34f9772e
1 // Copyright (c) 2015 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.
5 #include "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/location.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/task_runner_util.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chromeos/policy/system_log_uploader.h"
17 #include "chrome/browser/chromeos/policy/upload_job_impl.h"
18 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
19 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "components/policy/core/browser/browser_policy_connector.h"
22 #include "components/policy/core/common/cloud/enterprise_metrics.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/http/http_request_headers.h"
25 #include "third_party/re2/re2/re2.h"
27 namespace {
28 // The maximum number of successive retries.
29 const int kMaxNumRetries = 1;
31 // String constant defining the url tail we upload system logs to.
32 const char* kSystemLogUploadUrlTail = "/upload";
34 // The file names of the system logs to upload.
35 // Note: do not add anything to this list without checking for PII in the file.
36 const char* const kSystemLogFileNames[] = {
37 "/var/log/bios_info.txt", "/var/log/chrome/chrome",
38 "/var/log/eventlog.txt", "/var/log/messages",
39 "/var/log/net.log", "/var/log/platform_info.txt",
40 "/var/log/ui/ui.LATEST", "/var/log/update_engine.log"};
42 const char kEmailAddress[] =
43 "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}\\@"
44 "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+";
45 const char kIPAddress[] =
46 "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])"
47 "\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2"
48 "[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
49 "[0-9]{2}|[1-9][0-9]|[0-9]))";
50 const char kIPv6Address[] =
51 "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"
52 "([0-9a-fA-F]{1,4}:){1,7}:|"
53 "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
54 "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"
55 "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"
56 "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"
57 "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"
58 "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"
59 ":((:[0-9a-fA-F]{1,4}){1,7}|:)|"
60 "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"
61 "::(ffff(:0{1,4}){0,1}:){0,1}"
62 "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}"
63 "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"
64 "([0-9a-fA-F]{1,4}:){1,4}:"
65 "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}"
66 "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
68 const char kWebUrl[] = "(http|https|Http|Https|rtsp|Rtsp):\\/\\/";
70 // Reads the system log files as binary files, stores the files as pairs
71 // (file name, data) and returns. Called on blocking thread.
72 scoped_ptr<policy::SystemLogUploader::SystemLogs> ReadFiles() {
73 scoped_ptr<policy::SystemLogUploader::SystemLogs> system_logs(
74 new policy::SystemLogUploader::SystemLogs());
75 for (auto const file_path : kSystemLogFileNames) {
76 if (!base::PathExists(base::FilePath(file_path)))
77 continue;
78 std::string data = std::string();
79 if (!base::ReadFileToString(base::FilePath(file_path), &data)) {
80 LOG(ERROR) << "Failed to read the system log file from the disk "
81 << file_path << std::endl;
83 system_logs->push_back(std::make_pair(
84 file_path, policy::SystemLogUploader::RemoveSensitiveData(data)));
86 return system_logs.Pass();
89 // An implementation of the |SystemLogUploader::Delegate|, that is used to
90 // create an upload job and load system logs from the disk.
91 class SystemLogDelegate : public policy::SystemLogUploader::Delegate {
92 public:
93 SystemLogDelegate();
94 ~SystemLogDelegate() override;
96 // SystemLogUploader::Delegate:
97 void LoadSystemLogs(const LogUploadCallback& upload_callback) override;
99 scoped_ptr<policy::UploadJob> CreateUploadJob(
100 const GURL& upload_url,
101 policy::UploadJob::Delegate* delegate) override;
103 private:
104 DISALLOW_COPY_AND_ASSIGN(SystemLogDelegate);
107 SystemLogDelegate::SystemLogDelegate() {}
109 SystemLogDelegate::~SystemLogDelegate() {}
111 void SystemLogDelegate::LoadSystemLogs(
112 const LogUploadCallback& upload_callback) {
113 // Run ReadFiles() in the thread that interacts with the file system and
114 // return system logs to |upload_callback| on the current thread.
115 base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
116 FROM_HERE, base::Bind(&ReadFiles),
117 upload_callback);
120 scoped_ptr<policy::UploadJob> SystemLogDelegate::CreateUploadJob(
121 const GURL& upload_url,
122 policy::UploadJob::Delegate* delegate) {
123 chromeos::DeviceOAuth2TokenService* device_oauth2_token_service =
124 chromeos::DeviceOAuth2TokenServiceFactory::Get();
126 scoped_refptr<net::URLRequestContextGetter> system_request_context =
127 g_browser_process->system_request_context();
128 std::string robot_account_id =
129 device_oauth2_token_service->GetRobotAccountId();
130 return scoped_ptr<policy::UploadJob>(new policy::UploadJobImpl(
131 upload_url, robot_account_id, device_oauth2_token_service,
132 system_request_context, delegate,
133 make_scoped_ptr(new policy::UploadJobImpl::RandomMimeBoundaryGenerator)));
136 // Returns the system log upload frequency.
137 base::TimeDelta GetUploadFrequency() {
138 base::TimeDelta upload_frequency(base::TimeDelta::FromMilliseconds(
139 policy::SystemLogUploader::kDefaultUploadDelayMs));
140 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
141 switches::kSystemLogUploadFrequency)) {
142 std::string string_value =
143 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
144 switches::kSystemLogUploadFrequency);
145 int frequency;
146 if (base::StringToInt(string_value, &frequency)) {
147 upload_frequency = base::TimeDelta::FromMilliseconds(frequency);
150 return upload_frequency;
153 void RecordSystemLogPIILeak(policy::SystemLogPIIType type) {
154 UMA_HISTOGRAM_ENUMERATION(policy::kMetricSystemLogPII, type,
155 policy::SYSTEM_LOG_PII_TYPE_SIZE);
158 std::string GetUploadUrl() {
159 return policy::BrowserPolicyConnector::GetDeviceManagementUrl() +
160 kSystemLogUploadUrlTail;
163 } // namespace
165 namespace policy {
167 // Determines the time between log uploads.
168 const int64 SystemLogUploader::kDefaultUploadDelayMs =
169 12 * 60 * 60 * 1000; // 12 hours
171 // Determines the time, measured from the time of last failed upload,
172 // after which the log upload is retried.
173 const int64 SystemLogUploader::kErrorUploadDelayMs = 120 * 1000; // 120 seconds
175 // String constant identifying the header field which stores the file type.
176 const char* const SystemLogUploader::kFileTypeHeaderName = "File-Type";
178 // String constant signalling that the data segment contains log files.
179 const char* const SystemLogUploader::kFileTypeLogFile = "log_file";
181 // String constant signalling that the segment contains a plain text.
182 const char* const SystemLogUploader::kContentTypePlainText = "text/plain";
184 // Template string constant for populating the name field.
185 const char* const SystemLogUploader::kNameFieldTemplate = "file%d";
187 SystemLogUploader::SystemLogUploader(
188 scoped_ptr<Delegate> syslog_delegate,
189 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
190 : retry_count_(0),
191 upload_frequency_(GetUploadFrequency()),
192 task_runner_(task_runner),
193 syslog_delegate_(syslog_delegate.Pass()),
194 upload_enabled_(false),
195 weak_factory_(this) {
196 if (!syslog_delegate_)
197 syslog_delegate_.reset(new SystemLogDelegate());
198 DCHECK(syslog_delegate_);
200 // Watch for policy changes.
201 upload_enabled_observer_ = chromeos::CrosSettings::Get()->AddSettingsObserver(
202 chromeos::kLogUploadEnabled,
203 base::Bind(&SystemLogUploader::RefreshUploadSettings,
204 base::Unretained(this)));
206 // Fetch the current value of the policy.
207 RefreshUploadSettings();
209 // Immediately schedule the next system log upload (last_upload_attempt_ is
210 // set to the start of the epoch, so this will trigger an update upload in the
211 // immediate future).
212 ScheduleNextSystemLogUpload(upload_frequency_);
215 SystemLogUploader::~SystemLogUploader() {}
217 void SystemLogUploader::OnSuccess() {
218 upload_job_.reset();
219 last_upload_attempt_ = base::Time::NowFromSystemTime();
220 retry_count_ = 0;
222 // On successful log upload schedule the next log upload after
223 // upload_frequency_ time from now.
224 ScheduleNextSystemLogUpload(upload_frequency_);
227 void SystemLogUploader::OnFailure(UploadJob::ErrorCode error_code) {
228 upload_job_.reset();
229 last_upload_attempt_ = base::Time::NowFromSystemTime();
231 // If we have hit the maximum number of retries, terminate this upload
232 // attempt and schedule the next one using the normal delay. Otherwise, retry
233 // uploading after kErrorUploadDelayMs milliseconds.
234 if (retry_count_++ < kMaxNumRetries) {
235 ScheduleNextSystemLogUpload(
236 base::TimeDelta::FromMilliseconds(kErrorUploadDelayMs));
237 } else {
238 // No more retries.
239 retry_count_ = 0;
240 ScheduleNextSystemLogUpload(upload_frequency_);
244 // static
245 std::string SystemLogUploader::RemoveSensitiveData(const std::string& data) {
246 std::string result = "";
247 RE2 email_pattern(kEmailAddress), ipv4_pattern(kIPAddress),
248 ipv6_pattern(kIPv6Address), url_pattern(kWebUrl);
250 for (const std::string& line : base::SplitString(
251 data, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
252 // Email.
253 if (RE2::PartialMatch(line, email_pattern)) {
254 RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_EMAIL_ADDRESS);
255 continue;
258 // IPv4 address.
259 if (RE2::PartialMatch(line, ipv4_pattern)) {
260 RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_IP_ADDRESS);
261 continue;
264 // IPv6 address.
265 if (RE2::PartialMatch(line, ipv6_pattern)) {
266 RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_IP_ADDRESS);
267 continue;
270 // URL.
271 if (RE2::PartialMatch(line, url_pattern)) {
272 RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_WEB_URL);
273 continue;
276 // SSID.
277 if (line.find("SSID=") != std::string::npos) {
278 RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_SSID);
279 continue;
282 result += line + "\n";
284 return result;
287 void SystemLogUploader::RefreshUploadSettings() {
288 // Attempt to fetch the current value of the reporting settings.
289 // If trusted values are not available, register this function to be called
290 // back when they are available.
291 chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
292 if (chromeos::CrosSettingsProvider::TRUSTED !=
293 settings->PrepareTrustedValues(
294 base::Bind(&SystemLogUploader::RefreshUploadSettings,
295 weak_factory_.GetWeakPtr()))) {
296 return;
299 // CrosSettings are trusted - we want to use the last trusted values, by
300 // default do not upload system logs.
301 if (!settings->GetBoolean(chromeos::kLogUploadEnabled, &upload_enabled_))
302 upload_enabled_ = false;
305 void SystemLogUploader::UploadSystemLogs(scoped_ptr<SystemLogs> system_logs) {
306 // Must be called on the main thread.
307 DCHECK(thread_checker_.CalledOnValidThread());
308 DCHECK(!upload_job_);
310 GURL upload_url(GetUploadUrl());
311 DCHECK(upload_url.is_valid());
312 upload_job_ = syslog_delegate_->CreateUploadJob(upload_url, this);
314 // Start a system log upload.
315 int file_number = 1;
316 for (const auto& syslog_entry : *system_logs) {
317 std::map<std::string, std::string> header_fields;
318 scoped_ptr<std::string> data =
319 make_scoped_ptr(new std::string(syslog_entry.second));
320 header_fields.insert(std::make_pair(kFileTypeHeaderName, kFileTypeLogFile));
321 header_fields.insert(std::make_pair(net::HttpRequestHeaders::kContentType,
322 kContentTypePlainText));
323 upload_job_->AddDataSegment(
324 base::StringPrintf(kNameFieldTemplate, file_number), syslog_entry.first,
325 header_fields, data.Pass());
326 ++file_number;
328 upload_job_->Start();
331 void SystemLogUploader::StartLogUpload() {
332 // Must be called on the main thread.
333 DCHECK(thread_checker_.CalledOnValidThread());
335 if (upload_enabled_) {
336 syslog_delegate_->LoadSystemLogs(base::Bind(
337 &SystemLogUploader::UploadSystemLogs, weak_factory_.GetWeakPtr()));
338 } else {
339 // If upload is disabled, schedule the next attempt after 12h.
340 retry_count_ = 0;
341 last_upload_attempt_ = base::Time::NowFromSystemTime();
342 ScheduleNextSystemLogUpload(upload_frequency_);
346 void SystemLogUploader::ScheduleNextSystemLogUpload(base::TimeDelta frequency) {
347 // Calculate when to fire off the next update.
348 base::TimeDelta delay = std::max(
349 (last_upload_attempt_ + frequency) - base::Time::NowFromSystemTime(),
350 base::TimeDelta());
351 // Ensure that we never have more than one pending delayed task.
352 weak_factory_.InvalidateWeakPtrs();
353 task_runner_->PostDelayedTask(FROM_HERE,
354 base::Bind(&SystemLogUploader::StartLogUpload,
355 weak_factory_.GetWeakPtr()),
356 delay);
359 } // namespace policy