1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/omaha_request_action.h"
18 
19 #include <inttypes.h>
20 
21 #include <map>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include <base/bind.h>
28 #include <base/logging.h>
29 #include <base/rand_util.h>
30 #include <base/strings/string_number_conversions.h>
31 #include <base/strings/string_split.h>
32 #include <base/strings/string_util.h>
33 #include <base/strings/stringprintf.h>
34 #include <base/time/time.h>
35 #include <brillo/key_value_store.h>
36 #include <expat.h>
37 #include <metrics/metrics_library.h>
38 
39 #include "update_engine/common/action_pipe.h"
40 #include "update_engine/common/constants.h"
41 #include "update_engine/common/hardware_interface.h"
42 #include "update_engine/common/hash_calculator.h"
43 #include "update_engine/common/platform_constants.h"
44 #include "update_engine/common/prefs_interface.h"
45 #include "update_engine/common/utils.h"
46 #include "update_engine/connection_manager_interface.h"
47 #include "update_engine/metrics_reporter_interface.h"
48 #include "update_engine/metrics_utils.h"
49 #include "update_engine/omaha_request_params.h"
50 #include "update_engine/p2p_manager.h"
51 #include "update_engine/payload_state_interface.h"
52 
53 using base::Time;
54 using base::TimeDelta;
55 using std::map;
56 using std::string;
57 using std::vector;
58 
59 namespace chromeos_update_engine {
60 
61 // List of custom pair tags that we interpret in the Omaha Response:
62 static const char* kTagDeadline = "deadline";
63 static const char* kTagDisablePayloadBackoff = "DisablePayloadBackoff";
64 static const char* kTagVersion = "version";
65 // Deprecated: "IsDelta"
66 static const char* kTagIsDeltaPayload = "IsDeltaPayload";
67 static const char* kTagMaxFailureCountPerUrl = "MaxFailureCountPerUrl";
68 static const char* kTagMaxDaysToScatter = "MaxDaysToScatter";
69 // Deprecated: "ManifestSignatureRsa"
70 // Deprecated: "ManifestSize"
71 static const char* kTagMetadataSignatureRsa = "MetadataSignatureRsa";
72 static const char* kTagMetadataSize = "MetadataSize";
73 static const char* kTagMoreInfo = "MoreInfo";
74 // Deprecated: "NeedsAdmin"
75 static const char* kTagPrompt = "Prompt";
76 static const char* kTagDisableP2PForDownloading = "DisableP2PForDownloading";
77 static const char* kTagDisableP2PForSharing = "DisableP2PForSharing";
78 static const char* kTagPublicKeyRsa = "PublicKeyRsa";
79 
80 static const char* kOmahaUpdaterVersion = "0.1.0.0";
81 
82 // X-GoogleUpdate headers.
83 static const char* kXGoogleUpdateInteractivity = "X-GoogleUpdate-Interactivity";
84 static const char* kXGoogleUpdateAppId = "X-GoogleUpdate-AppId";
85 static const char* kXGoogleUpdateUpdater = "X-GoogleUpdate-Updater";
86 
87 // updatecheck attributes (without the underscore prefix).
88 static const char* kEolAttr = "eol";
89 
90 namespace {
91 
92 // Returns an XML ping element attribute assignment with attribute
93 // |name| and value |ping_days| if |ping_days| has a value that needs
94 // to be sent, or an empty string otherwise.
GetPingAttribute(const string & name,int ping_days)95 string GetPingAttribute(const string& name, int ping_days) {
96   if (ping_days > 0 || ping_days == OmahaRequestAction::kNeverPinged)
97     return base::StringPrintf(" %s=\"%d\"", name.c_str(), ping_days);
98   return "";
99 }
100 
101 // Returns an XML ping element if any of the elapsed days need to be
102 // sent, or an empty string otherwise.
GetPingXml(int ping_active_days,int ping_roll_call_days)103 string GetPingXml(int ping_active_days, int ping_roll_call_days) {
104   string ping_active = GetPingAttribute("a", ping_active_days);
105   string ping_roll_call = GetPingAttribute("r", ping_roll_call_days);
106   if (!ping_active.empty() || !ping_roll_call.empty()) {
107     return base::StringPrintf("        <ping active=\"1\"%s%s></ping>\n",
108                               ping_active.c_str(),
109                               ping_roll_call.c_str());
110   }
111   return "";
112 }
113 
114 // Returns an XML that goes into the body of the <app> element of the Omaha
115 // request based on the given parameters.
GetAppBody(const OmahaEvent * event,OmahaRequestParams * params,bool ping_only,bool include_ping,int ping_active_days,int ping_roll_call_days,PrefsInterface * prefs)116 string GetAppBody(const OmahaEvent* event,
117                   OmahaRequestParams* params,
118                   bool ping_only,
119                   bool include_ping,
120                   int ping_active_days,
121                   int ping_roll_call_days,
122                   PrefsInterface* prefs) {
123   string app_body;
124   if (event == nullptr) {
125     if (include_ping)
126         app_body = GetPingXml(ping_active_days, ping_roll_call_days);
127     if (!ping_only) {
128       app_body += base::StringPrintf(
129           "        <updatecheck targetversionprefix=\"%s\""
130           "></updatecheck>\n",
131           XmlEncodeWithDefault(params->target_version_prefix(), "").c_str());
132 
133       // If this is the first update check after a reboot following a previous
134       // update, generate an event containing the previous version number. If
135       // the previous version preference file doesn't exist the event is still
136       // generated with a previous version of 0.0.0.0 -- this is relevant for
137       // older clients or new installs. The previous version event is not sent
138       // for ping-only requests because they come before the client has
139       // rebooted. The previous version event is also not sent if it was already
140       // sent for this new version with a previous updatecheck.
141       string prev_version;
142       if (!prefs->GetString(kPrefsPreviousVersion, &prev_version)) {
143         prev_version = "0.0.0.0";
144       }
145       // We only store a non-empty previous version value after a successful
146       // update in the previous boot. After reporting it back to the server,
147       // we clear the previous version value so it doesn't get reported again.
148       if (!prev_version.empty()) {
149         app_body += base::StringPrintf(
150             "        <event eventtype=\"%d\" eventresult=\"%d\" "
151             "previousversion=\"%s\"></event>\n",
152             OmahaEvent::kTypeRebootedAfterUpdate,
153             OmahaEvent::kResultSuccess,
154             XmlEncodeWithDefault(prev_version, "0.0.0.0").c_str());
155         LOG_IF(WARNING, !prefs->SetString(kPrefsPreviousVersion, ""))
156             << "Unable to reset the previous version.";
157       }
158     }
159   } else {
160     // The error code is an optional attribute so append it only if the result
161     // is not success.
162     string error_code;
163     if (event->result != OmahaEvent::kResultSuccess) {
164       error_code = base::StringPrintf(" errorcode=\"%d\"",
165                                       static_cast<int>(event->error_code));
166     }
167     app_body = base::StringPrintf(
168         "        <event eventtype=\"%d\" eventresult=\"%d\"%s></event>\n",
169         event->type, event->result, error_code.c_str());
170   }
171 
172   return app_body;
173 }
174 
175 // Returns the cohort* argument to include in the <app> tag for the passed
176 // |arg_name| and |prefs_key|, if any. The return value is suitable to
177 // concatenate to the list of arguments and includes a space at the end.
GetCohortArgXml(PrefsInterface * prefs,const string arg_name,const string prefs_key)178 string GetCohortArgXml(PrefsInterface* prefs,
179                        const string arg_name,
180                        const string prefs_key) {
181   // There's nothing wrong with not having a given cohort setting, so we check
182   // existance first to avoid the warning log message.
183   if (!prefs->Exists(prefs_key))
184     return "";
185   string cohort_value;
186   if (!prefs->GetString(prefs_key, &cohort_value) || cohort_value.empty())
187     return "";
188   // This is a sanity check to avoid sending a huge XML file back to Ohama due
189   // to a compromised stateful partition making the update check fail in low
190   // network environments envent after a reboot.
191   if (cohort_value.size() > 1024) {
192     LOG(WARNING) << "The omaha cohort setting " << arg_name
193                  << " has a too big value, which must be an error or an "
194                     "attacker trying to inhibit updates.";
195     return "";
196   }
197 
198   string escaped_xml_value;
199   if (!XmlEncode(cohort_value, &escaped_xml_value)) {
200     LOG(WARNING) << "The omaha cohort setting " << arg_name
201                  << " is ASCII-7 invalid, ignoring it.";
202     return "";
203   }
204 
205   return base::StringPrintf("%s=\"%s\" ",
206                             arg_name.c_str(), escaped_xml_value.c_str());
207 }
208 
209 struct OmahaAppData {
210   string id;
211   string version;
212   string product_components;
213 };
214 
IsValidComponentID(const string & id)215 bool IsValidComponentID(const string& id) {
216   for (char c : id) {
217     if (!isalnum(c) && c != '-' && c != '_' && c != '.')
218       return false;
219   }
220   return true;
221 }
222 
223 // Returns an XML that corresponds to the entire <app> node of the Omaha
224 // request based on the given parameters.
GetAppXml(const OmahaEvent * event,OmahaRequestParams * params,const OmahaAppData & app_data,bool ping_only,bool include_ping,int ping_active_days,int ping_roll_call_days,int install_date_in_days,SystemState * system_state)225 string GetAppXml(const OmahaEvent* event,
226                  OmahaRequestParams* params,
227                  const OmahaAppData& app_data,
228                  bool ping_only,
229                  bool include_ping,
230                  int ping_active_days,
231                  int ping_roll_call_days,
232                  int install_date_in_days,
233                  SystemState* system_state) {
234   string app_body = GetAppBody(event, params, ping_only, include_ping,
235                                ping_active_days, ping_roll_call_days,
236                                system_state->prefs());
237   string app_versions;
238 
239   // If we are downgrading to a more stable channel and we are allowed to do
240   // powerwash, then pass 0.0.0.0 as the version. This is needed to get the
241   // highest-versioned payload on the destination channel.
242   if (params->ShouldPowerwash()) {
243     LOG(INFO) << "Passing OS version as 0.0.0.0 as we are set to powerwash "
244               << "on downgrading to the version in the more stable channel";
245     app_versions = "version=\"0.0.0.0\" from_version=\"" +
246                    XmlEncodeWithDefault(app_data.version, "0.0.0.0") + "\" ";
247   } else {
248     app_versions = "version=\"" +
249                    XmlEncodeWithDefault(app_data.version, "0.0.0.0") + "\" ";
250   }
251 
252   string download_channel = params->download_channel();
253   string app_channels =
254       "track=\"" + XmlEncodeWithDefault(download_channel, "") + "\" ";
255   if (params->current_channel() != download_channel) {
256     app_channels += "from_track=\"" + XmlEncodeWithDefault(
257         params->current_channel(), "") + "\" ";
258   }
259 
260   string delta_okay_str = params->delta_okay() ? "true" : "false";
261 
262   // If install_date_days is not set (e.g. its value is -1 ), don't
263   // include the attribute.
264   string install_date_in_days_str = "";
265   if (install_date_in_days >= 0) {
266     install_date_in_days_str = base::StringPrintf("installdate=\"%d\" ",
267                                                   install_date_in_days);
268   }
269 
270   string app_cohort_args;
271   app_cohort_args += GetCohortArgXml(system_state->prefs(),
272                                      "cohort", kPrefsOmahaCohort);
273   app_cohort_args += GetCohortArgXml(system_state->prefs(),
274                                      "cohorthint", kPrefsOmahaCohortHint);
275   app_cohort_args += GetCohortArgXml(system_state->prefs(),
276                                      "cohortname", kPrefsOmahaCohortName);
277 
278   string fingerprint_arg;
279   if (!params->os_build_fingerprint().empty()) {
280     fingerprint_arg = "fingerprint=\"" +
281                       XmlEncodeWithDefault(params->os_build_fingerprint(), "") +
282                       "\" ";
283   }
284 
285   string buildtype_arg;
286   if (!params->os_build_type().empty()) {
287     buildtype_arg = "os_build_type=\"" +
288                     XmlEncodeWithDefault(params->os_build_type(), "") + "\" ";
289   }
290 
291   string product_components_args;
292   if (!params->ShouldPowerwash() && !app_data.product_components.empty()) {
293     brillo::KeyValueStore store;
294     if (store.LoadFromString(app_data.product_components)) {
295       for (const string& key : store.GetKeys()) {
296         if (!IsValidComponentID(key)) {
297           LOG(ERROR) << "Invalid component id: " << key;
298           continue;
299         }
300         string version;
301         if (!store.GetString(key, &version)) {
302           LOG(ERROR) << "Failed to get version for " << key
303                      << " in product_components.";
304           continue;
305         }
306         product_components_args +=
307             base::StringPrintf("_%s.version=\"%s\" ",
308                                key.c_str(),
309                                XmlEncodeWithDefault(version, "").c_str());
310       }
311     } else {
312       LOG(ERROR) << "Failed to parse product_components:\n"
313                  << app_data.product_components;
314     }
315   }
316 
317   // clang-format off
318   string app_xml = "    <app "
319       "appid=\"" + XmlEncodeWithDefault(app_data.id, "") + "\" " +
320       app_cohort_args +
321       app_versions +
322       app_channels +
323       product_components_args +
324       fingerprint_arg +
325       buildtype_arg +
326       "lang=\"" + XmlEncodeWithDefault(params->app_lang(), "en-US") + "\" " +
327       "board=\"" + XmlEncodeWithDefault(params->os_board(), "") + "\" " +
328       "hardware_class=\"" + XmlEncodeWithDefault(params->hwid(), "") + "\" " +
329       "delta_okay=\"" + delta_okay_str + "\" "
330       "fw_version=\"" + XmlEncodeWithDefault(params->fw_version(), "") + "\" " +
331       "ec_version=\"" + XmlEncodeWithDefault(params->ec_version(), "") + "\" " +
332       install_date_in_days_str +
333       ">\n" +
334          app_body +
335       "    </app>\n";
336   // clang-format on
337   return app_xml;
338 }
339 
340 // Returns an XML that corresponds to the entire <os> node of the Omaha
341 // request based on the given parameters.
GetOsXml(OmahaRequestParams * params)342 string GetOsXml(OmahaRequestParams* params) {
343   string os_xml ="    <os "
344       "version=\"" + XmlEncodeWithDefault(params->os_version(), "") + "\" " +
345       "platform=\"" + XmlEncodeWithDefault(params->os_platform(), "") + "\" " +
346       "sp=\"" + XmlEncodeWithDefault(params->os_sp(), "") + "\">"
347       "</os>\n";
348   return os_xml;
349 }
350 
351 // Returns an XML that corresponds to the entire Omaha request based on the
352 // given parameters.
GetRequestXml(const OmahaEvent * event,OmahaRequestParams * params,bool ping_only,bool include_ping,int ping_active_days,int ping_roll_call_days,int install_date_in_days,SystemState * system_state)353 string GetRequestXml(const OmahaEvent* event,
354                      OmahaRequestParams* params,
355                      bool ping_only,
356                      bool include_ping,
357                      int ping_active_days,
358                      int ping_roll_call_days,
359                      int install_date_in_days,
360                      SystemState* system_state) {
361   string os_xml = GetOsXml(params);
362   OmahaAppData product_app = {
363       .id = params->GetAppId(),
364       .version = params->app_version(),
365       .product_components = params->product_components()};
366   string app_xml = GetAppXml(event,
367                              params,
368                              product_app,
369                              ping_only,
370                              include_ping,
371                              ping_active_days,
372                              ping_roll_call_days,
373                              install_date_in_days,
374                              system_state);
375   if (!params->system_app_id().empty()) {
376     OmahaAppData system_app = {.id = params->system_app_id(),
377                                .version = params->system_version()};
378     app_xml += GetAppXml(event,
379                          params,
380                          system_app,
381                          ping_only,
382                          include_ping,
383                          ping_active_days,
384                          ping_roll_call_days,
385                          install_date_in_days,
386                          system_state);
387   }
388 
389   string install_source = base::StringPrintf("installsource=\"%s\" ",
390       (params->interactive() ? "ondemandupdate" : "scheduler"));
391 
392   string updater_version = XmlEncodeWithDefault(
393       base::StringPrintf("%s-%s",
394                          constants::kOmahaUpdaterID,
395                          kOmahaUpdaterVersion), "");
396   string request_xml =
397       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
398       "<request protocol=\"3.0\" " + (
399           "version=\"" + updater_version + "\" "
400           "updaterversion=\"" + updater_version + "\" " +
401           install_source +
402           "ismachine=\"1\">\n") +
403       os_xml +
404       app_xml +
405       "</request>\n";
406 
407   return request_xml;
408 }
409 
410 }  // namespace
411 
412 // Struct used for holding data obtained when parsing the XML.
413 struct OmahaParserData {
OmahaParserDatachromeos_update_engine::OmahaParserData414   explicit OmahaParserData(XML_Parser _xml_parser) : xml_parser(_xml_parser) {}
415 
416   // Pointer to the expat XML_Parser object.
417   XML_Parser xml_parser;
418 
419   // This is the state of the parser as it's processing the XML.
420   bool failed = false;
421   bool entity_decl = false;
422   string current_path;
423 
424   // These are the values extracted from the XML.
425   string updatecheck_poll_interval;
426   map<string, string> updatecheck_attrs;
427   string daystart_elapsed_days;
428   string daystart_elapsed_seconds;
429 
430   struct App {
431     string id;
432     vector<string> url_codebase;
433     string manifest_version;
434     map<string, string> action_postinstall_attrs;
435     string updatecheck_status;
436     string cohort;
437     string cohorthint;
438     string cohortname;
439     bool cohort_set = false;
440     bool cohorthint_set = false;
441     bool cohortname_set = false;
442 
443     struct Package {
444       string name;
445       string size;
446       string hash;
447     };
448     vector<Package> packages;
449   };
450   vector<App> apps;
451 };
452 
453 namespace {
454 
455 // Callback function invoked by expat.
ParserHandlerStart(void * user_data,const XML_Char * element,const XML_Char ** attr)456 void ParserHandlerStart(void* user_data, const XML_Char* element,
457                         const XML_Char** attr) {
458   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
459 
460   if (data->failed)
461     return;
462 
463   data->current_path += string("/") + element;
464 
465   map<string, string> attrs;
466   if (attr != nullptr) {
467     for (int n = 0; attr[n] != nullptr && attr[n+1] != nullptr; n += 2) {
468       string key = attr[n];
469       string value = attr[n + 1];
470       attrs[key] = value;
471     }
472   }
473 
474   if (data->current_path == "/response/app") {
475     OmahaParserData::App app;
476     if (attrs.find("appid") != attrs.end()) {
477       app.id = attrs["appid"];
478     }
479     if (attrs.find("cohort") != attrs.end()) {
480       app.cohort_set = true;
481       app.cohort = attrs["cohort"];
482     }
483     if (attrs.find("cohorthint") != attrs.end()) {
484       app.cohorthint_set = true;
485       app.cohorthint = attrs["cohorthint"];
486     }
487     if (attrs.find("cohortname") != attrs.end()) {
488       app.cohortname_set = true;
489       app.cohortname = attrs["cohortname"];
490     }
491     data->apps.push_back(std::move(app));
492   } else if (data->current_path == "/response/app/updatecheck") {
493     if (!data->apps.empty())
494       data->apps.back().updatecheck_status = attrs["status"];
495     if (data->updatecheck_poll_interval.empty())
496       data->updatecheck_poll_interval = attrs["PollInterval"];
497     // Omaha sends arbitrary key-value pairs as extra attributes starting with
498     // an underscore.
499     for (const auto& attr : attrs) {
500       if (!attr.first.empty() && attr.first[0] == '_')
501         data->updatecheck_attrs[attr.first.substr(1)] = attr.second;
502     }
503   } else if (data->current_path == "/response/daystart") {
504     // Get the install-date.
505     data->daystart_elapsed_days = attrs["elapsed_days"];
506     data->daystart_elapsed_seconds = attrs["elapsed_seconds"];
507   } else if (data->current_path == "/response/app/updatecheck/urls/url") {
508     // Look at all <url> elements.
509     if (!data->apps.empty())
510       data->apps.back().url_codebase.push_back(attrs["codebase"]);
511   } else if (data->current_path ==
512              "/response/app/updatecheck/manifest/packages/package") {
513     // Look at all <package> elements.
514     if (!data->apps.empty())
515       data->apps.back().packages.push_back({.name = attrs["name"],
516                                             .size = attrs["size"],
517                                             .hash = attrs["hash_sha256"]});
518   } else if (data->current_path == "/response/app/updatecheck/manifest") {
519     // Get the version.
520     if (!data->apps.empty())
521       data->apps.back().manifest_version = attrs[kTagVersion];
522   } else if (data->current_path ==
523              "/response/app/updatecheck/manifest/actions/action") {
524     // We only care about the postinstall action.
525     if (attrs["event"] == "postinstall" && !data->apps.empty()) {
526       data->apps.back().action_postinstall_attrs = std::move(attrs);
527     }
528   }
529 }
530 
531 // Callback function invoked by expat.
ParserHandlerEnd(void * user_data,const XML_Char * element)532 void ParserHandlerEnd(void* user_data, const XML_Char* element) {
533   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
534   if (data->failed)
535     return;
536 
537   const string path_suffix = string("/") + element;
538 
539   if (!base::EndsWith(data->current_path, path_suffix,
540                       base::CompareCase::SENSITIVE)) {
541     LOG(ERROR) << "Unexpected end element '" << element
542                << "' with current_path='" << data->current_path << "'";
543     data->failed = true;
544     return;
545   }
546   data->current_path.resize(data->current_path.size() - path_suffix.size());
547 }
548 
549 // Callback function invoked by expat.
550 //
551 // This is called for entity declarations. Since Omaha is guaranteed
552 // to never return any XML with entities our course of action is to
553 // just stop parsing. This avoids potential resource exhaustion
554 // problems AKA the "billion laughs". CVE-2013-0340.
ParserHandlerEntityDecl(void * user_data,const XML_Char * entity_name,int is_parameter_entity,const XML_Char * value,int value_length,const XML_Char * base,const XML_Char * system_id,const XML_Char * public_id,const XML_Char * notation_name)555 void ParserHandlerEntityDecl(void *user_data,
556                              const XML_Char *entity_name,
557                              int is_parameter_entity,
558                              const XML_Char *value,
559                              int value_length,
560                              const XML_Char *base,
561                              const XML_Char *system_id,
562                              const XML_Char *public_id,
563                              const XML_Char *notation_name) {
564   OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
565 
566   LOG(ERROR) << "XML entities are not supported. Aborting parsing.";
567   data->failed = true;
568   data->entity_decl = true;
569   XML_StopParser(data->xml_parser, false);
570 }
571 
572 }  // namespace
573 
XmlEncode(const string & input,string * output)574 bool XmlEncode(const string& input, string* output) {
575   if (std::find_if(input.begin(), input.end(),
576                    [](const char c){return c & 0x80;}) != input.end()) {
577     LOG(WARNING) << "Invalid ASCII-7 string passed to the XML encoder:";
578     utils::HexDumpString(input);
579     return false;
580   }
581   output->clear();
582   // We need at least input.size() space in the output, but the code below will
583   // handle it if we need more.
584   output->reserve(input.size());
585   for (char c : input) {
586     switch (c) {
587       case '\"':
588         output->append("&quot;");
589         break;
590       case '\'':
591         output->append("&apos;");
592         break;
593       case '&':
594         output->append("&amp;");
595         break;
596       case '<':
597         output->append("&lt;");
598         break;
599       case '>':
600         output->append("&gt;");
601         break;
602       default:
603         output->push_back(c);
604     }
605   }
606   return true;
607 }
608 
XmlEncodeWithDefault(const string & input,const string & default_value)609 string XmlEncodeWithDefault(const string& input, const string& default_value) {
610   string output;
611   if (XmlEncode(input, &output))
612     return output;
613   return default_value;
614 }
615 
OmahaRequestAction(SystemState * system_state,OmahaEvent * event,std::unique_ptr<HttpFetcher> http_fetcher,bool ping_only)616 OmahaRequestAction::OmahaRequestAction(
617     SystemState* system_state,
618     OmahaEvent* event,
619     std::unique_ptr<HttpFetcher> http_fetcher,
620     bool ping_only)
621     : system_state_(system_state),
622       event_(event),
623       http_fetcher_(std::move(http_fetcher)),
624       ping_only_(ping_only),
625       ping_active_days_(0),
626       ping_roll_call_days_(0) {
627   params_ = system_state->request_params();
628 }
629 
~OmahaRequestAction()630 OmahaRequestAction::~OmahaRequestAction() {}
631 
632 // Calculates the value to use for the ping days parameter.
CalculatePingDays(const string & key)633 int OmahaRequestAction::CalculatePingDays(const string& key) {
634   int days = kNeverPinged;
635   int64_t last_ping = 0;
636   if (system_state_->prefs()->GetInt64(key, &last_ping) && last_ping >= 0) {
637     days = (Time::Now() - Time::FromInternalValue(last_ping)).InDays();
638     if (days < 0) {
639       // If |days| is negative, then the system clock must have jumped
640       // back in time since the ping was sent. Mark the value so that
641       // it doesn't get sent to the server but we still update the
642       // last ping daystart preference. This way the next ping time
643       // will be correct, hopefully.
644       days = kPingTimeJump;
645       LOG(WARNING) <<
646           "System clock jumped back in time. Resetting ping daystarts.";
647     }
648   }
649   return days;
650 }
651 
InitPingDays()652 void OmahaRequestAction::InitPingDays() {
653   // We send pings only along with update checks, not with events.
654   if (IsEvent()) {
655     return;
656   }
657   // TODO(petkov): Figure a way to distinguish active use pings
658   // vs. roll call pings. Currently, the two pings are identical. A
659   // fix needs to change this code as well as UpdateLastPingDays and ShouldPing.
660   ping_active_days_ = CalculatePingDays(kPrefsLastActivePingDay);
661   ping_roll_call_days_ = CalculatePingDays(kPrefsLastRollCallPingDay);
662 }
663 
ShouldPing() const664 bool OmahaRequestAction::ShouldPing() const {
665   if (ping_active_days_ == OmahaRequestAction::kNeverPinged &&
666       ping_roll_call_days_ == OmahaRequestAction::kNeverPinged) {
667     int powerwash_count = system_state_->hardware()->GetPowerwashCount();
668     if (powerwash_count > 0) {
669       LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
670                 << "powerwash_count is " << powerwash_count;
671       return false;
672     }
673     if (system_state_->hardware()->GetFirstActiveOmahaPingSent()) {
674       LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
675                 << "the first_active_omaha_ping_sent is true";
676       return false;
677     }
678     return true;
679   }
680   return ping_active_days_ > 0 || ping_roll_call_days_ > 0;
681 }
682 
683 // static
GetInstallDate(SystemState * system_state)684 int OmahaRequestAction::GetInstallDate(SystemState* system_state) {
685   PrefsInterface* prefs = system_state->prefs();
686   if (prefs == nullptr)
687     return -1;
688 
689   // If we have the value stored on disk, just return it.
690   int64_t stored_value;
691   if (prefs->GetInt64(kPrefsInstallDateDays, &stored_value)) {
692     // Convert and sanity-check.
693     int install_date_days = static_cast<int>(stored_value);
694     if (install_date_days >= 0)
695       return install_date_days;
696     LOG(ERROR) << "Dropping stored Omaha InstallData since its value num_days="
697                << install_date_days << " looks suspicious.";
698     prefs->Delete(kPrefsInstallDateDays);
699   }
700 
701   // Otherwise, if OOBE is not complete then do nothing and wait for
702   // ParseResponse() to call ParseInstallDate() and then
703   // PersistInstallDate() to set the kPrefsInstallDateDays state
704   // variable. Once that is done, we'll then report back in future
705   // Omaha requests.  This works exactly because OOBE triggers an
706   // update check.
707   //
708   // However, if OOBE is complete and the kPrefsInstallDateDays state
709   // variable is not set, there are two possibilities
710   //
711   //   1. The update check in OOBE failed so we never got a response
712   //      from Omaha (no network etc.); or
713   //
714   //   2. OOBE was done on an older version that didn't write to the
715   //      kPrefsInstallDateDays state variable.
716   //
717   // In both cases, we approximate the install date by simply
718   // inspecting the timestamp of when OOBE happened.
719 
720   Time time_of_oobe;
721   if (!system_state->hardware()->IsOOBEEnabled() ||
722       !system_state->hardware()->IsOOBEComplete(&time_of_oobe)) {
723     LOG(INFO) << "Not generating Omaha InstallData as we have "
724               << "no prefs file and OOBE is not complete or not enabled.";
725     return -1;
726   }
727 
728   int num_days;
729   if (!utils::ConvertToOmahaInstallDate(time_of_oobe, &num_days)) {
730     LOG(ERROR) << "Not generating Omaha InstallData from time of OOBE "
731                << "as its value '" << utils::ToString(time_of_oobe)
732                << "' looks suspicious.";
733     return -1;
734   }
735 
736   // Persist this to disk, for future use.
737   if (!OmahaRequestAction::PersistInstallDate(system_state,
738                                               num_days,
739                                               kProvisionedFromOOBEMarker))
740     return -1;
741 
742   LOG(INFO) << "Set the Omaha InstallDate from OOBE time-stamp to "
743             << num_days << " days";
744 
745   return num_days;
746 }
747 
PerformAction()748 void OmahaRequestAction::PerformAction() {
749   http_fetcher_->set_delegate(this);
750   InitPingDays();
751   if (ping_only_ && !ShouldPing()) {
752     processor_->ActionComplete(this, ErrorCode::kSuccess);
753     return;
754   }
755 
756   string request_post(GetRequestXml(event_.get(),
757                                     params_,
758                                     ping_only_,
759                                     ShouldPing(),  // include_ping
760                                     ping_active_days_,
761                                     ping_roll_call_days_,
762                                     GetInstallDate(system_state_),
763                                     system_state_));
764 
765   // Set X-GoogleUpdate headers.
766   http_fetcher_->SetHeader(kXGoogleUpdateInteractivity,
767                            params_->interactive() ? "fg" : "bg");
768   http_fetcher_->SetHeader(kXGoogleUpdateAppId, params_->GetAppId());
769   http_fetcher_->SetHeader(
770       kXGoogleUpdateUpdater,
771       base::StringPrintf(
772           "%s-%s", constants::kOmahaUpdaterID, kOmahaUpdaterVersion));
773 
774   http_fetcher_->SetPostData(request_post.data(), request_post.size(),
775                              kHttpContentTypeTextXml);
776   LOG(INFO) << "Posting an Omaha request to " << params_->update_url();
777   LOG(INFO) << "Request: " << request_post;
778   http_fetcher_->BeginTransfer(params_->update_url());
779 }
780 
TerminateProcessing()781 void OmahaRequestAction::TerminateProcessing() {
782   http_fetcher_->TerminateTransfer();
783 }
784 
785 // We just store the response in the buffer. Once we've received all bytes,
786 // we'll look in the buffer and decide what to do.
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)787 void OmahaRequestAction::ReceivedBytes(HttpFetcher *fetcher,
788                                        const void* bytes,
789                                        size_t length) {
790   const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(bytes);
791   response_buffer_.insert(response_buffer_.end(), byte_ptr, byte_ptr + length);
792 }
793 
794 namespace {
795 
796 // Parses a 64 bit base-10 int from a string and returns it. Returns 0
797 // on error. If the string contains "0", that's indistinguishable from
798 // error.
ParseInt(const string & str)799 off_t ParseInt(const string& str) {
800   off_t ret = 0;
801   int rc = sscanf(str.c_str(), "%" PRIi64, &ret);  // NOLINT(runtime/printf)
802   if (rc < 1) {
803     // failure
804     return 0;
805   }
806   return ret;
807 }
808 
809 // Parses |str| and returns |true| if, and only if, its value is "true".
ParseBool(const string & str)810 bool ParseBool(const string& str) {
811   return str == "true";
812 }
813 
814 // Update the last ping day preferences based on the server daystart
815 // response. Returns true on success, false otherwise.
UpdateLastPingDays(OmahaParserData * parser_data,PrefsInterface * prefs)816 bool UpdateLastPingDays(OmahaParserData *parser_data, PrefsInterface* prefs) {
817   int64_t elapsed_seconds = 0;
818   TEST_AND_RETURN_FALSE(
819       base::StringToInt64(parser_data->daystart_elapsed_seconds,
820                           &elapsed_seconds));
821   TEST_AND_RETURN_FALSE(elapsed_seconds >= 0);
822 
823   // Remember the local time that matches the server's last midnight
824   // time.
825   Time daystart = Time::Now() - TimeDelta::FromSeconds(elapsed_seconds);
826   prefs->SetInt64(kPrefsLastActivePingDay, daystart.ToInternalValue());
827   prefs->SetInt64(kPrefsLastRollCallPingDay, daystart.ToInternalValue());
828   return true;
829 }
830 
831 // Parses the package node in the given XML document and populates
832 // |output_object| if valid. Returns true if we should continue the parsing.
833 // False otherwise, in which case it sets any error code using |completer|.
ParsePackage(OmahaParserData::App * app,OmahaResponse * output_object,ScopedActionCompleter * completer)834 bool ParsePackage(OmahaParserData::App* app,
835                   OmahaResponse* output_object,
836                   ScopedActionCompleter* completer) {
837   if (app->updatecheck_status == "noupdate") {
838     if (!app->packages.empty()) {
839       LOG(ERROR) << "No update in this <app> but <package> is not empty.";
840       completer->set_code(ErrorCode::kOmahaResponseInvalid);
841       return false;
842     }
843     return true;
844   }
845   if (app->packages.empty()) {
846     LOG(ERROR) << "Omaha Response has no packages";
847     completer->set_code(ErrorCode::kOmahaResponseInvalid);
848     return false;
849   }
850   if (app->url_codebase.empty()) {
851     LOG(ERROR) << "No Omaha Response URLs";
852     completer->set_code(ErrorCode::kOmahaResponseInvalid);
853     return false;
854   }
855   LOG(INFO) << "Found " << app->url_codebase.size() << " url(s)";
856   vector<string> metadata_sizes =
857       base::SplitString(app->action_postinstall_attrs[kTagMetadataSize],
858                         ":",
859                         base::TRIM_WHITESPACE,
860                         base::SPLIT_WANT_ALL);
861   vector<string> metadata_signatures =
862       base::SplitString(app->action_postinstall_attrs[kTagMetadataSignatureRsa],
863                         ":",
864                         base::TRIM_WHITESPACE,
865                         base::SPLIT_WANT_ALL);
866   vector<string> is_delta_payloads =
867       base::SplitString(app->action_postinstall_attrs[kTagIsDeltaPayload],
868                         ":",
869                         base::TRIM_WHITESPACE,
870                         base::SPLIT_WANT_ALL);
871   for (size_t i = 0; i < app->packages.size(); i++) {
872     const auto& package = app->packages[i];
873     if (package.name.empty()) {
874       LOG(ERROR) << "Omaha Response has empty package name";
875       completer->set_code(ErrorCode::kOmahaResponseInvalid);
876       return false;
877     }
878     LOG(INFO) << "Found package " << package.name;
879 
880     OmahaResponse::Package out_package;
881     for (const string& codebase : app->url_codebase) {
882       if (codebase.empty()) {
883         LOG(ERROR) << "Omaha Response URL has empty codebase";
884         completer->set_code(ErrorCode::kOmahaResponseInvalid);
885         return false;
886       }
887       out_package.payload_urls.push_back(codebase + package.name);
888     }
889     // Parse the payload size.
890     base::StringToUint64(package.size, &out_package.size);
891     if (out_package.size <= 0) {
892       LOG(ERROR) << "Omaha Response has invalid payload size: " << package.size;
893       completer->set_code(ErrorCode::kOmahaResponseInvalid);
894       return false;
895     }
896     LOG(INFO) << "Payload size = " << out_package.size << " bytes";
897 
898     if (i < metadata_sizes.size())
899       base::StringToUint64(metadata_sizes[i], &out_package.metadata_size);
900     LOG(INFO) << "Payload metadata size = " << out_package.metadata_size
901               << " bytes";
902 
903     if (i < metadata_signatures.size())
904       out_package.metadata_signature = metadata_signatures[i];
905     LOG(INFO) << "Payload metadata signature = "
906               << out_package.metadata_signature;
907 
908     out_package.hash = package.hash;
909     if (out_package.hash.empty()) {
910       LOG(ERROR) << "Omaha Response has empty hash_sha256 value";
911       completer->set_code(ErrorCode::kOmahaResponseInvalid);
912       return false;
913     }
914     LOG(INFO) << "Payload hash = " << out_package.hash;
915 
916     if (i < is_delta_payloads.size())
917       out_package.is_delta = ParseBool(is_delta_payloads[i]);
918     LOG(INFO) << "Payload is delta = " << utils::ToString(out_package.is_delta);
919 
920     output_object->packages.push_back(std::move(out_package));
921   }
922 
923   return true;
924 }
925 
926 }  // namespace
927 
ParseResponse(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)928 bool OmahaRequestAction::ParseResponse(OmahaParserData* parser_data,
929                                        OmahaResponse* output_object,
930                                        ScopedActionCompleter* completer) {
931   if (parser_data->apps.empty()) {
932     completer->set_code(ErrorCode::kOmahaResponseInvalid);
933     return false;
934   }
935   LOG(INFO) << "Found " << parser_data->apps.size() << " <app>.";
936 
937   // chromium-os:37289: The PollInterval is not supported by Omaha server
938   // currently.  But still keeping this existing code in case we ever decide to
939   // slow down the request rate from the server-side. Note that the PollInterval
940   // is not persisted, so it has to be sent by the server on every response to
941   // guarantee that the scheduler uses this value (otherwise, if the device got
942   // rebooted after the last server-indicated value, it'll revert to the default
943   // value). Also kDefaultMaxUpdateChecks value for the scattering logic is
944   // based on the assumption that we perform an update check every hour so that
945   // the max value of 8 will roughly be equivalent to one work day. If we decide
946   // to use PollInterval permanently, we should update the
947   // max_update_checks_allowed to take PollInterval into account.  Note: The
948   // parsing for PollInterval happens even before parsing of the status because
949   // we may want to specify the PollInterval even when there's no update.
950   base::StringToInt(parser_data->updatecheck_poll_interval,
951                     &output_object->poll_interval);
952 
953   // Check for the "elapsed_days" attribute in the "daystart"
954   // element. This is the number of days since Jan 1 2007, 0:00
955   // PST. If we don't have a persisted value of the Omaha InstallDate,
956   // we'll use it to calculate it and then persist it.
957   if (ParseInstallDate(parser_data, output_object) &&
958       !HasInstallDate(system_state_)) {
959     // Since output_object->install_date_days is never negative, the
960     // elapsed_days -> install-date calculation is reduced to simply
961     // rounding down to the nearest number divisible by 7.
962     int remainder = output_object->install_date_days % 7;
963     int install_date_days_rounded =
964         output_object->install_date_days - remainder;
965     if (PersistInstallDate(system_state_,
966                            install_date_days_rounded,
967                            kProvisionedFromOmahaResponse)) {
968       LOG(INFO) << "Set the Omaha InstallDate from Omaha Response to "
969                 << install_date_days_rounded << " days";
970     }
971   }
972 
973   // We persist the cohorts sent by omaha even if the status is "noupdate".
974   for (const auto& app : parser_data->apps) {
975     if (app.id == params_->GetAppId()) {
976       if (app.cohort_set)
977         PersistCohortData(kPrefsOmahaCohort, app.cohort);
978       if (app.cohorthint_set)
979         PersistCohortData(kPrefsOmahaCohortHint, app.cohorthint);
980       if (app.cohortname_set)
981         PersistCohortData(kPrefsOmahaCohortName, app.cohortname);
982       break;
983     }
984   }
985 
986   // Parse the updatecheck attributes.
987   PersistEolStatus(parser_data->updatecheck_attrs);
988 
989   if (!ParseStatus(parser_data, output_object, completer))
990     return false;
991 
992   if (!ParseParams(parser_data, output_object, completer))
993     return false;
994 
995   // Package has to be parsed after Params now because ParseParams need to make
996   // sure that postinstall action exists.
997   for (auto& app : parser_data->apps)
998     if (!ParsePackage(&app, output_object, completer))
999       return false;
1000 
1001   return true;
1002 }
1003 
ParseStatus(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)1004 bool OmahaRequestAction::ParseStatus(OmahaParserData* parser_data,
1005                                      OmahaResponse* output_object,
1006                                      ScopedActionCompleter* completer) {
1007   output_object->update_exists = false;
1008   for (size_t i = 0; i < parser_data->apps.size(); i++) {
1009     const string& status = parser_data->apps[i].updatecheck_status;
1010     if (status == "noupdate") {
1011       // Don't update if any app has status="noupdate".
1012       LOG(INFO) << "No update for <app> " << i;
1013       output_object->update_exists = false;
1014       break;
1015     } else if (status == "ok") {
1016       if (parser_data->apps[i].action_postinstall_attrs["noupdate"] == "true") {
1017         // noupdate="true" in postinstall attributes means it's an update to
1018         // self, only update if there's at least one app really have update.
1019         LOG(INFO) << "Update to self for <app> " << i;
1020       } else {
1021         LOG(INFO) << "Update for <app> " << i;
1022         output_object->update_exists = true;
1023       }
1024     } else {
1025       LOG(ERROR) << "Unknown Omaha response status: " << status;
1026       completer->set_code(ErrorCode::kOmahaResponseInvalid);
1027       return false;
1028     }
1029   }
1030   if (!output_object->update_exists) {
1031     SetOutputObject(*output_object);
1032     completer->set_code(ErrorCode::kSuccess);
1033   }
1034 
1035   return output_object->update_exists;
1036 }
1037 
ParseParams(OmahaParserData * parser_data,OmahaResponse * output_object,ScopedActionCompleter * completer)1038 bool OmahaRequestAction::ParseParams(OmahaParserData* parser_data,
1039                                      OmahaResponse* output_object,
1040                                      ScopedActionCompleter* completer) {
1041   map<string, string> attrs;
1042   for (auto& app : parser_data->apps) {
1043     if (app.id == params_->GetAppId()) {
1044       // this is the app (potentially the only app)
1045       output_object->version = app.manifest_version;
1046     } else if (!params_->system_app_id().empty() &&
1047                app.id == params_->system_app_id()) {
1048       // this is the system app (this check is intentionally skipped if there is
1049       // no system_app_id set)
1050       output_object->system_version = app.manifest_version;
1051     }
1052     if (!app.action_postinstall_attrs.empty() && attrs.empty()) {
1053       attrs = app.action_postinstall_attrs;
1054     }
1055   }
1056   if (output_object->version.empty()) {
1057     LOG(ERROR) << "Omaha Response does not have version in manifest!";
1058     completer->set_code(ErrorCode::kOmahaResponseInvalid);
1059     return false;
1060   }
1061 
1062   LOG(INFO) << "Received omaha response to update to version "
1063             << output_object->version;
1064 
1065   if (attrs.empty()) {
1066     LOG(ERROR) << "Omaha Response has no postinstall event action";
1067     completer->set_code(ErrorCode::kOmahaResponseInvalid);
1068     return false;
1069   }
1070 
1071   // Get the optional properties one by one.
1072   output_object->more_info_url = attrs[kTagMoreInfo];
1073   output_object->prompt = ParseBool(attrs[kTagPrompt]);
1074   output_object->deadline = attrs[kTagDeadline];
1075   output_object->max_days_to_scatter = ParseInt(attrs[kTagMaxDaysToScatter]);
1076   output_object->disable_p2p_for_downloading =
1077       ParseBool(attrs[kTagDisableP2PForDownloading]);
1078   output_object->disable_p2p_for_sharing =
1079       ParseBool(attrs[kTagDisableP2PForSharing]);
1080   output_object->public_key_rsa = attrs[kTagPublicKeyRsa];
1081 
1082   string max = attrs[kTagMaxFailureCountPerUrl];
1083   if (!base::StringToUint(max, &output_object->max_failure_count_per_url))
1084     output_object->max_failure_count_per_url = kDefaultMaxFailureCountPerUrl;
1085 
1086   output_object->disable_payload_backoff =
1087       ParseBool(attrs[kTagDisablePayloadBackoff]);
1088 
1089   return true;
1090 }
1091 
1092 // If the transfer was successful, this uses expat to parse the response
1093 // and fill in the appropriate fields of the output object. Also, notifies
1094 // the processor that we're done.
TransferComplete(HttpFetcher * fetcher,bool successful)1095 void OmahaRequestAction::TransferComplete(HttpFetcher *fetcher,
1096                                           bool successful) {
1097   ScopedActionCompleter completer(processor_, this);
1098   string current_response(response_buffer_.begin(), response_buffer_.end());
1099   LOG(INFO) << "Omaha request response: " << current_response;
1100 
1101   PayloadStateInterface* const payload_state = system_state_->payload_state();
1102 
1103   // Events are best effort transactions -- assume they always succeed.
1104   if (IsEvent()) {
1105     CHECK(!HasOutputPipe()) << "No output pipe allowed for event requests.";
1106     completer.set_code(ErrorCode::kSuccess);
1107     return;
1108   }
1109 
1110   if (!successful) {
1111     LOG(ERROR) << "Omaha request network transfer failed.";
1112     int code = GetHTTPResponseCode();
1113     // Makes sure we send sane error values.
1114     if (code < 0 || code >= 1000) {
1115       code = 999;
1116     }
1117     completer.set_code(static_cast<ErrorCode>(
1118         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + code));
1119     return;
1120   }
1121 
1122   XML_Parser parser = XML_ParserCreate(nullptr);
1123   OmahaParserData parser_data(parser);
1124   XML_SetUserData(parser, &parser_data);
1125   XML_SetElementHandler(parser, ParserHandlerStart, ParserHandlerEnd);
1126   XML_SetEntityDeclHandler(parser, ParserHandlerEntityDecl);
1127   XML_Status res = XML_Parse(
1128       parser,
1129       reinterpret_cast<const char*>(response_buffer_.data()),
1130       response_buffer_.size(),
1131       XML_TRUE);
1132   XML_ParserFree(parser);
1133 
1134   if (res != XML_STATUS_OK || parser_data.failed) {
1135     LOG(ERROR) << "Omaha response not valid XML: "
1136                << XML_ErrorString(XML_GetErrorCode(parser))
1137                << " at line " << XML_GetCurrentLineNumber(parser)
1138                << " col " << XML_GetCurrentColumnNumber(parser);
1139     ErrorCode error_code = ErrorCode::kOmahaRequestXMLParseError;
1140     if (response_buffer_.empty()) {
1141       error_code = ErrorCode::kOmahaRequestEmptyResponseError;
1142     } else if (parser_data.entity_decl) {
1143       error_code = ErrorCode::kOmahaRequestXMLHasEntityDecl;
1144     }
1145     completer.set_code(error_code);
1146     return;
1147   }
1148 
1149   // Update the last ping day preferences based on the server daystart response
1150   // even if we didn't send a ping. Omaha always includes the daystart in the
1151   // response, but log the error if it didn't.
1152   LOG_IF(ERROR, !UpdateLastPingDays(&parser_data, system_state_->prefs()))
1153       << "Failed to update the last ping day preferences!";
1154 
1155   // Sets first_active_omaha_ping_sent to true (vpd in CrOS). We only do this if
1156   // we have got a response from omaha and if its value has never been set to
1157   // true before. Failure of this function should be ignored. There should be no
1158   // need to check if a=-1 has been sent because older devices have already sent
1159   // their a=-1 in the past and we have to set first_active_omaha_ping_sent for
1160   // future checks.
1161   if (!system_state_->hardware()->GetFirstActiveOmahaPingSent()) {
1162     system_state_->hardware()->SetFirstActiveOmahaPingSent();
1163   }
1164 
1165   if (!HasOutputPipe()) {
1166     // Just set success to whether or not the http transfer succeeded,
1167     // which must be true at this point in the code.
1168     completer.set_code(ErrorCode::kSuccess);
1169     return;
1170   }
1171 
1172   OmahaResponse output_object;
1173   if (!ParseResponse(&parser_data, &output_object, &completer))
1174     return;
1175   output_object.update_exists = true;
1176   SetOutputObject(output_object);
1177 
1178   if (ShouldIgnoreUpdate(output_object)) {
1179     output_object.update_exists = false;
1180     completer.set_code(ErrorCode::kOmahaUpdateIgnoredPerPolicy);
1181     return;
1182   }
1183 
1184   // If Omaha says to disable p2p, respect that
1185   if (output_object.disable_p2p_for_downloading) {
1186     LOG(INFO) << "Forcibly disabling use of p2p for downloading as "
1187               << "requested by Omaha.";
1188     payload_state->SetUsingP2PForDownloading(false);
1189   }
1190   if (output_object.disable_p2p_for_sharing) {
1191     LOG(INFO) << "Forcibly disabling use of p2p for sharing as "
1192               << "requested by Omaha.";
1193     payload_state->SetUsingP2PForSharing(false);
1194   }
1195 
1196   // Update the payload state with the current response. The payload state
1197   // will automatically reset all stale state if this response is different
1198   // from what's stored already. We are updating the payload state as late
1199   // as possible in this method so that if a new release gets pushed and then
1200   // got pulled back due to some issues, we don't want to clear our internal
1201   // state unnecessarily.
1202   payload_state->SetResponse(output_object);
1203 
1204   // It could be we've already exceeded the deadline for when p2p is
1205   // allowed or that we've tried too many times with p2p. Check that.
1206   if (payload_state->GetUsingP2PForDownloading()) {
1207     payload_state->P2PNewAttempt();
1208     if (!payload_state->P2PAttemptAllowed()) {
1209       LOG(INFO) << "Forcibly disabling use of p2p for downloading because "
1210                 << "of previous failures when using p2p.";
1211       payload_state->SetUsingP2PForDownloading(false);
1212     }
1213   }
1214 
1215   // From here on, we'll complete stuff in CompleteProcessing() so
1216   // disable |completer| since we'll create a new one in that
1217   // function.
1218   completer.set_should_complete(false);
1219 
1220   // If we're allowed to use p2p for downloading we do not pay
1221   // attention to wall-clock-based waiting if the URL is indeed
1222   // available via p2p. Therefore, check if the file is available via
1223   // p2p before deferring...
1224   if (payload_state->GetUsingP2PForDownloading()) {
1225     LookupPayloadViaP2P(output_object);
1226   } else {
1227     CompleteProcessing();
1228   }
1229 }
1230 
CompleteProcessing()1231 void OmahaRequestAction::CompleteProcessing() {
1232   ScopedActionCompleter completer(processor_, this);
1233   OmahaResponse& output_object = const_cast<OmahaResponse&>(GetOutputObject());
1234   PayloadStateInterface* payload_state = system_state_->payload_state();
1235 
1236   if (system_state_->hardware()->IsOOBEEnabled() &&
1237       !system_state_->hardware()->IsOOBEComplete(nullptr) &&
1238       output_object.deadline.empty() &&
1239       params_->app_version() != "ForcedUpdate") {
1240     output_object.update_exists = false;
1241     LOG(INFO) << "Ignoring non-critical Omaha updates until OOBE is done.";
1242     completer.set_code(ErrorCode::kNonCriticalUpdateInOOBE);
1243     return;
1244   }
1245 
1246   if (ShouldDeferDownload(&output_object)) {
1247     output_object.update_exists = false;
1248     LOG(INFO) << "Ignoring Omaha updates as updates are deferred by policy.";
1249     completer.set_code(ErrorCode::kOmahaUpdateDeferredPerPolicy);
1250     return;
1251   }
1252 
1253   if (payload_state->ShouldBackoffDownload()) {
1254     output_object.update_exists = false;
1255     LOG(INFO) << "Ignoring Omaha updates in order to backoff our retry "
1256               << "attempts";
1257     completer.set_code(ErrorCode::kOmahaUpdateDeferredForBackoff);
1258     return;
1259   }
1260   completer.set_code(ErrorCode::kSuccess);
1261 }
1262 
OnLookupPayloadViaP2PCompleted(const string & url)1263 void OmahaRequestAction::OnLookupPayloadViaP2PCompleted(const string& url) {
1264   LOG(INFO) << "Lookup complete, p2p-client returned URL '" << url << "'";
1265   if (!url.empty()) {
1266     system_state_->payload_state()->SetP2PUrl(url);
1267   } else {
1268     LOG(INFO) << "Forcibly disabling use of p2p for downloading "
1269               << "because no suitable peer could be found.";
1270     system_state_->payload_state()->SetUsingP2PForDownloading(false);
1271   }
1272   CompleteProcessing();
1273 }
1274 
LookupPayloadViaP2P(const OmahaResponse & response)1275 void OmahaRequestAction::LookupPayloadViaP2P(const OmahaResponse& response) {
1276   // If the device is in the middle of an update, the state variables
1277   // kPrefsUpdateStateNextDataOffset, kPrefsUpdateStateNextDataLength
1278   // tracks the offset and length of the operation currently in
1279   // progress. The offset is based from the end of the manifest which
1280   // is kPrefsManifestMetadataSize bytes long.
1281   //
1282   // To make forward progress and avoid deadlocks, we need to find a
1283   // peer that has at least the entire operation we're currently
1284   // working on. Otherwise we may end up in a situation where two
1285   // devices bounce back and forth downloading from each other,
1286   // neither making any forward progress until one of them decides to
1287   // stop using p2p (via kMaxP2PAttempts and kMaxP2PAttemptTimeSeconds
1288   // safe-guards). See http://crbug.com/297170 for an example)
1289   size_t minimum_size = 0;
1290   int64_t manifest_metadata_size = 0;
1291   int64_t manifest_signature_size = 0;
1292   int64_t next_data_offset = 0;
1293   int64_t next_data_length = 0;
1294   if (system_state_ &&
1295       system_state_->prefs()->GetInt64(kPrefsManifestMetadataSize,
1296                                        &manifest_metadata_size) &&
1297       manifest_metadata_size != -1 &&
1298       system_state_->prefs()->GetInt64(kPrefsManifestSignatureSize,
1299                                        &manifest_signature_size) &&
1300       manifest_signature_size != -1 &&
1301       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataOffset,
1302                                        &next_data_offset) &&
1303       next_data_offset != -1 &&
1304       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataLength,
1305                                        &next_data_length)) {
1306     minimum_size = manifest_metadata_size + manifest_signature_size +
1307                    next_data_offset + next_data_length;
1308   }
1309 
1310   // TODO(senj): Fix P2P for multiple package.
1311   brillo::Blob raw_hash;
1312   if (!base::HexStringToBytes(response.packages[0].hash, &raw_hash))
1313     return;
1314   string file_id =
1315       utils::CalculateP2PFileId(raw_hash, response.packages[0].size);
1316   if (system_state_->p2p_manager()) {
1317     LOG(INFO) << "Checking if payload is available via p2p, file_id=" << file_id
1318               << " minimum_size=" << minimum_size;
1319     system_state_->p2p_manager()->LookupUrlForFile(
1320         file_id,
1321         minimum_size,
1322         TimeDelta::FromSeconds(kMaxP2PNetworkWaitTimeSeconds),
1323         base::Bind(&OmahaRequestAction::OnLookupPayloadViaP2PCompleted,
1324                    base::Unretained(this)));
1325   }
1326 }
1327 
ShouldDeferDownload(OmahaResponse * output_object)1328 bool OmahaRequestAction::ShouldDeferDownload(OmahaResponse* output_object) {
1329   if (params_->interactive()) {
1330     LOG(INFO) << "Not deferring download because update is interactive.";
1331     return false;
1332   }
1333 
1334   // If we're using p2p to download _and_ we have a p2p URL, we never
1335   // defer the download. This is because the download will always
1336   // happen from a peer on the LAN and we've been waiting in line for
1337   // our turn.
1338   const PayloadStateInterface* payload_state = system_state_->payload_state();
1339   if (payload_state->GetUsingP2PForDownloading() &&
1340       !payload_state->GetP2PUrl().empty()) {
1341     LOG(INFO) << "Download not deferred because download "
1342               << "will happen from a local peer (via p2p).";
1343     return false;
1344   }
1345 
1346   // We should defer the downloads only if we've first satisfied the
1347   // wall-clock-based-waiting period and then the update-check-based waiting
1348   // period, if required.
1349   if (!params_->wall_clock_based_wait_enabled()) {
1350     LOG(INFO) << "Wall-clock-based waiting period is not enabled,"
1351               << " so no deferring needed.";
1352     return false;
1353   }
1354 
1355   switch (IsWallClockBasedWaitingSatisfied(output_object)) {
1356     case kWallClockWaitNotSatisfied:
1357       // We haven't even satisfied the first condition, passing the
1358       // wall-clock-based waiting period, so we should defer the downloads
1359       // until that happens.
1360       LOG(INFO) << "wall-clock-based-wait not satisfied.";
1361       return true;
1362 
1363     case kWallClockWaitDoneButUpdateCheckWaitRequired:
1364       LOG(INFO) << "wall-clock-based-wait satisfied and "
1365                 << "update-check-based-wait required.";
1366       return !IsUpdateCheckCountBasedWaitingSatisfied();
1367 
1368     case kWallClockWaitDoneAndUpdateCheckWaitNotRequired:
1369       // Wall-clock-based waiting period is satisfied, and it's determined
1370       // that we do not need the update-check-based wait. so no need to
1371       // defer downloads.
1372       LOG(INFO) << "wall-clock-based-wait satisfied and "
1373                 << "update-check-based-wait is not required.";
1374       return false;
1375 
1376     default:
1377       // Returning false for this default case so we err on the
1378       // side of downloading updates than deferring in case of any bugs.
1379       NOTREACHED();
1380       return false;
1381   }
1382 }
1383 
1384 OmahaRequestAction::WallClockWaitResult
IsWallClockBasedWaitingSatisfied(OmahaResponse * output_object)1385 OmahaRequestAction::IsWallClockBasedWaitingSatisfied(
1386     OmahaResponse* output_object) {
1387   Time update_first_seen_at;
1388   int64_t update_first_seen_at_int;
1389 
1390   if (system_state_->prefs()->Exists(kPrefsUpdateFirstSeenAt)) {
1391     if (system_state_->prefs()->GetInt64(kPrefsUpdateFirstSeenAt,
1392                                          &update_first_seen_at_int)) {
1393       // Note: This timestamp could be that of ANY update we saw in the past
1394       // (not necessarily this particular update we're considering to apply)
1395       // but never got to apply because of some reason (e.g. stop AU policy,
1396       // updates being pulled out from Omaha, changes in target version prefix,
1397       // new update being rolled out, etc.). But for the purposes of scattering
1398       // it doesn't matter which update the timestamp corresponds to. i.e.
1399       // the clock starts ticking the first time we see an update and we're
1400       // ready to apply when the random wait period is satisfied relative to
1401       // that first seen timestamp.
1402       update_first_seen_at = Time::FromInternalValue(update_first_seen_at_int);
1403       LOG(INFO) << "Using persisted value of UpdateFirstSeenAt: "
1404                 << utils::ToString(update_first_seen_at);
1405     } else {
1406       // This seems like an unexpected error where the persisted value exists
1407       // but it's not readable for some reason. Just skip scattering in this
1408       // case to be safe.
1409      LOG(INFO) << "Not scattering as UpdateFirstSeenAt value cannot be read";
1410      return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1411     }
1412   } else {
1413     update_first_seen_at = system_state_->clock()->GetWallclockTime();
1414     update_first_seen_at_int = update_first_seen_at.ToInternalValue();
1415     if (system_state_->prefs()->SetInt64(kPrefsUpdateFirstSeenAt,
1416                                          update_first_seen_at_int)) {
1417       LOG(INFO) << "Persisted the new value for UpdateFirstSeenAt: "
1418                 << utils::ToString(update_first_seen_at);
1419     } else {
1420       // This seems like an unexpected error where the value cannot be
1421       // persisted for some reason. Just skip scattering in this
1422       // case to be safe.
1423       LOG(INFO) << "Not scattering as UpdateFirstSeenAt value "
1424                 << utils::ToString(update_first_seen_at)
1425                 << " cannot be persisted";
1426      return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1427     }
1428   }
1429 
1430   TimeDelta elapsed_time =
1431       system_state_->clock()->GetWallclockTime() - update_first_seen_at;
1432   TimeDelta max_scatter_period =
1433       TimeDelta::FromDays(output_object->max_days_to_scatter);
1434 
1435   LOG(INFO) << "Waiting Period = "
1436             << utils::FormatSecs(params_->waiting_period().InSeconds())
1437             << ", Time Elapsed = "
1438             << utils::FormatSecs(elapsed_time.InSeconds())
1439             << ", MaxDaysToScatter = "
1440             << max_scatter_period.InDays();
1441 
1442   if (!output_object->deadline.empty()) {
1443     // The deadline is set for all rules which serve a delta update from a
1444     // previous FSI, which means this update will be applied mostly in OOBE
1445     // cases. For these cases, we shouldn't scatter so as to finish the OOBE
1446     // quickly.
1447     LOG(INFO) << "Not scattering as deadline flag is set";
1448     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1449   }
1450 
1451   if (max_scatter_period.InDays() == 0) {
1452     // This means the Omaha rule creator decides that this rule
1453     // should not be scattered irrespective of the policy.
1454     LOG(INFO) << "Not scattering as MaxDaysToScatter in rule is 0.";
1455     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1456   }
1457 
1458   if (elapsed_time > max_scatter_period) {
1459     // This means we've waited more than the upperbound wait in the rule
1460     // from the time we first saw a valid update available to us.
1461     // This will prevent update starvation.
1462     LOG(INFO) << "Not scattering as we're past the MaxDaysToScatter limit.";
1463     return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1464   }
1465 
1466   // This means we are required to participate in scattering.
1467   // See if our turn has arrived now.
1468   TimeDelta remaining_wait_time = params_->waiting_period() - elapsed_time;
1469   if (remaining_wait_time.InSeconds() <= 0) {
1470     // Yes, it's our turn now.
1471     LOG(INFO) << "Successfully passed the wall-clock-based-wait.";
1472 
1473     // But we can't download until the update-check-count-based wait is also
1474     // satisfied, so mark it as required now if update checks are enabled.
1475     return params_->update_check_count_wait_enabled() ?
1476               kWallClockWaitDoneButUpdateCheckWaitRequired :
1477               kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
1478   }
1479 
1480   // Not our turn yet, so we have to wait until our turn to
1481   // help scatter the downloads across all clients of the enterprise.
1482   LOG(INFO) << "Update deferred for another "
1483             << utils::FormatSecs(remaining_wait_time.InSeconds())
1484             << " per policy.";
1485   return kWallClockWaitNotSatisfied;
1486 }
1487 
IsUpdateCheckCountBasedWaitingSatisfied()1488 bool OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied() {
1489   int64_t update_check_count_value;
1490 
1491   if (system_state_->prefs()->Exists(kPrefsUpdateCheckCount)) {
1492     if (!system_state_->prefs()->GetInt64(kPrefsUpdateCheckCount,
1493                                           &update_check_count_value)) {
1494       // We are unable to read the update check count from file for some reason.
1495       // So let's proceed anyway so as to not stall the update.
1496       LOG(ERROR) << "Unable to read update check count. "
1497                  << "Skipping update-check-count-based-wait.";
1498       return true;
1499     }
1500   } else {
1501     // This file does not exist. This means we haven't started our update
1502     // check count down yet, so this is the right time to start the count down.
1503     update_check_count_value = base::RandInt(
1504       params_->min_update_checks_needed(),
1505       params_->max_update_checks_allowed());
1506 
1507     LOG(INFO) << "Randomly picked update check count value = "
1508               << update_check_count_value;
1509 
1510     // Write out the initial value of update_check_count_value.
1511     if (!system_state_->prefs()->SetInt64(kPrefsUpdateCheckCount,
1512                                           update_check_count_value)) {
1513       // We weren't able to write the update check count file for some reason.
1514       // So let's proceed anyway so as to not stall the update.
1515       LOG(ERROR) << "Unable to write update check count. "
1516                  << "Skipping update-check-count-based-wait.";
1517       return true;
1518     }
1519   }
1520 
1521   if (update_check_count_value == 0) {
1522     LOG(INFO) << "Successfully passed the update-check-based-wait.";
1523     return true;
1524   }
1525 
1526   if (update_check_count_value < 0 ||
1527       update_check_count_value > params_->max_update_checks_allowed()) {
1528     // We err on the side of skipping scattering logic instead of stalling
1529     // a machine from receiving any updates in case of any unexpected state.
1530     LOG(ERROR) << "Invalid value for update check count detected. "
1531                << "Skipping update-check-count-based-wait.";
1532     return true;
1533   }
1534 
1535   // Legal value, we need to wait for more update checks to happen
1536   // until this becomes 0.
1537   LOG(INFO) << "Deferring Omaha updates for another "
1538             << update_check_count_value
1539             << " update checks per policy";
1540   return false;
1541 }
1542 
1543 // static
ParseInstallDate(OmahaParserData * parser_data,OmahaResponse * output_object)1544 bool OmahaRequestAction::ParseInstallDate(OmahaParserData* parser_data,
1545                                           OmahaResponse* output_object) {
1546   int64_t elapsed_days = 0;
1547   if (!base::StringToInt64(parser_data->daystart_elapsed_days,
1548                            &elapsed_days))
1549     return false;
1550 
1551   if (elapsed_days < 0)
1552     return false;
1553 
1554   output_object->install_date_days = elapsed_days;
1555   return true;
1556 }
1557 
1558 // static
HasInstallDate(SystemState * system_state)1559 bool OmahaRequestAction::HasInstallDate(SystemState *system_state) {
1560   PrefsInterface* prefs = system_state->prefs();
1561   if (prefs == nullptr)
1562     return false;
1563 
1564   return prefs->Exists(kPrefsInstallDateDays);
1565 }
1566 
1567 // static
PersistInstallDate(SystemState * system_state,int install_date_days,InstallDateProvisioningSource source)1568 bool OmahaRequestAction::PersistInstallDate(
1569     SystemState *system_state,
1570     int install_date_days,
1571     InstallDateProvisioningSource source) {
1572   TEST_AND_RETURN_FALSE(install_date_days >= 0);
1573 
1574   PrefsInterface* prefs = system_state->prefs();
1575   if (prefs == nullptr)
1576     return false;
1577 
1578   if (!prefs->SetInt64(kPrefsInstallDateDays, install_date_days))
1579     return false;
1580 
1581   system_state->metrics_reporter()->ReportInstallDateProvisioningSource(
1582       static_cast<int>(source),  // Sample.
1583       kProvisionedMax);          // Maximum.
1584   return true;
1585 }
1586 
PersistCohortData(const string & prefs_key,const string & new_value)1587 bool OmahaRequestAction::PersistCohortData(
1588     const string& prefs_key,
1589     const string& new_value) {
1590   if (new_value.empty() && system_state_->prefs()->Exists(prefs_key)) {
1591     LOG(INFO) << "Removing stored " << prefs_key << " value.";
1592     return system_state_->prefs()->Delete(prefs_key);
1593   } else if (!new_value.empty()) {
1594     LOG(INFO) << "Storing new setting " << prefs_key << " as " << new_value;
1595     return system_state_->prefs()->SetString(prefs_key, new_value);
1596   }
1597   return true;
1598 }
1599 
PersistEolStatus(const map<string,string> & attrs)1600 bool OmahaRequestAction::PersistEolStatus(const map<string, string>& attrs) {
1601   auto eol_attr = attrs.find(kEolAttr);
1602   if (eol_attr != attrs.end()) {
1603     return system_state_->prefs()->SetString(kPrefsOmahaEolStatus,
1604                                              eol_attr->second);
1605   } else if (system_state_->prefs()->Exists(kPrefsOmahaEolStatus)) {
1606     return system_state_->prefs()->Delete(kPrefsOmahaEolStatus);
1607   }
1608   return true;
1609 }
1610 
ActionCompleted(ErrorCode code)1611 void OmahaRequestAction::ActionCompleted(ErrorCode code) {
1612   // We only want to report this on "update check".
1613   if (ping_only_ || event_ != nullptr)
1614     return;
1615 
1616   metrics::CheckResult result = metrics::CheckResult::kUnset;
1617   metrics::CheckReaction reaction = metrics::CheckReaction::kUnset;
1618   metrics::DownloadErrorCode download_error_code =
1619       metrics::DownloadErrorCode::kUnset;
1620 
1621   // Regular update attempt.
1622   switch (code) {
1623   case ErrorCode::kSuccess:
1624     // OK, we parsed the response successfully but that does
1625     // necessarily mean that an update is available.
1626     if (HasOutputPipe()) {
1627       const OmahaResponse& response = GetOutputObject();
1628       if (response.update_exists) {
1629         result = metrics::CheckResult::kUpdateAvailable;
1630         reaction = metrics::CheckReaction::kUpdating;
1631       } else {
1632         result = metrics::CheckResult::kNoUpdateAvailable;
1633       }
1634     } else {
1635       result = metrics::CheckResult::kNoUpdateAvailable;
1636     }
1637     break;
1638 
1639   case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
1640     result = metrics::CheckResult::kUpdateAvailable;
1641     reaction = metrics::CheckReaction::kIgnored;
1642     break;
1643 
1644   case ErrorCode::kOmahaUpdateDeferredPerPolicy:
1645     result = metrics::CheckResult::kUpdateAvailable;
1646     reaction = metrics::CheckReaction::kDeferring;
1647     break;
1648 
1649   case ErrorCode::kOmahaUpdateDeferredForBackoff:
1650     result = metrics::CheckResult::kUpdateAvailable;
1651     reaction = metrics::CheckReaction::kBackingOff;
1652     break;
1653 
1654   default:
1655     // We report two flavors of errors, "Download errors" and "Parsing
1656     // error". Try to convert to the former and if that doesn't work
1657     // we know it's the latter.
1658     metrics::DownloadErrorCode tmp_error =
1659         metrics_utils::GetDownloadErrorCode(code);
1660     if (tmp_error != metrics::DownloadErrorCode::kInputMalformed) {
1661       result = metrics::CheckResult::kDownloadError;
1662       download_error_code = tmp_error;
1663     } else {
1664       result = metrics::CheckResult::kParsingError;
1665     }
1666     break;
1667   }
1668 
1669   system_state_->metrics_reporter()->ReportUpdateCheckMetrics(
1670       system_state_, result, reaction, download_error_code);
1671 }
1672 
ShouldIgnoreUpdate(const OmahaResponse & response) const1673 bool OmahaRequestAction::ShouldIgnoreUpdate(
1674     const OmahaResponse& response) const {
1675   // Note: policy decision to not update to a version we rolled back from.
1676   string rollback_version =
1677       system_state_->payload_state()->GetRollbackVersion();
1678   if (!rollback_version.empty()) {
1679     LOG(INFO) << "Detected previous rollback from version " << rollback_version;
1680     if (rollback_version == response.version) {
1681       LOG(INFO) << "Received version that we rolled back from. Ignoring.";
1682       return true;
1683     }
1684   }
1685 
1686   if (!IsUpdateAllowedOverCurrentConnection()) {
1687     LOG(INFO) << "Update is not allowed over current connection.";
1688     return true;
1689   }
1690 
1691   // Note: We could technically delete the UpdateFirstSeenAt state when we
1692   // return true. If we do, it'll mean a device has to restart the
1693   // UpdateFirstSeenAt and thus help scattering take effect when the AU is
1694   // turned on again. On the other hand, it also increases the chance of update
1695   // starvation if an admin turns AU on/off more frequently. We choose to err on
1696   // the side of preventing starvation at the cost of not applying scattering in
1697   // those cases.
1698   return false;
1699 }
1700 
IsUpdateAllowedOverCurrentConnection() const1701 bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection() const {
1702   ConnectionType type;
1703   ConnectionTethering tethering;
1704   ConnectionManagerInterface* connection_manager =
1705       system_state_->connection_manager();
1706   if (!connection_manager->GetConnectionProperties(&type, &tethering)) {
1707     LOG(INFO) << "We could not determine our connection type. "
1708               << "Defaulting to allow updates.";
1709     return true;
1710   }
1711   bool is_allowed = connection_manager->IsUpdateAllowedOver(type, tethering);
1712   LOG(INFO) << "We are connected via "
1713             << connection_utils::StringForConnectionType(type)
1714             << ", Updates allowed: " << (is_allowed ? "Yes" : "No");
1715   return is_allowed;
1716 }
1717 
1718 }  // namespace chromeos_update_engine
1719