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 #ifndef UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
18 #define UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
19 
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 
24 #include <memory>
25 #include <string>
26 #include <vector>
27 
28 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
29 
30 #include <brillo/secure_blob.h>
31 #include <curl/curl.h>
32 
33 #include "update_engine/common/action.h"
34 #include "update_engine/common/http_fetcher.h"
35 #include "update_engine/omaha_response.h"
36 #include "update_engine/system_state.h"
37 
38 // The Omaha Request action makes a request to Omaha and can output
39 // the response on the output ActionPipe.
40 
41 namespace chromeos_update_engine {
42 
43 // Encodes XML entities in a given string. Input must be ASCII-7 valid. If
44 // the input is invalid, the default value is used instead.
45 std::string XmlEncodeWithDefault(const std::string& input,
46                                  const std::string& default_value);
47 
48 // Escapes text so it can be included as character data and attribute
49 // values. The |input| string must be valid ASCII-7, no UTF-8 supported.
50 // Returns whether the |input| was valid and escaped properly in |output|.
51 bool XmlEncode(const std::string& input, std::string* output);
52 
53 // This struct encapsulates the Omaha event information. For a
54 // complete list of defined event types and results, see
55 // http://code.google.com/p/omaha/wiki/ServerProtocol#event
56 struct OmahaEvent {
57   // The Type values correspond to EVENT_TYPE values of Omaha.
58   enum Type {
59     kTypeUnknown = 0,
60     kTypeDownloadComplete = 1,
61     kTypeInstallComplete = 2,
62     kTypeUpdateComplete = 3,
63     kTypeUpdateDownloadStarted = 13,
64     kTypeUpdateDownloadFinished = 14,
65     // Chromium OS reserved type sent after the first reboot following an update
66     // completed.
67     kTypeRebootedAfterUpdate = 54,
68   };
69 
70   // The Result values correspond to EVENT_RESULT values of Omaha.
71   enum Result {
72     kResultError = 0,
73     kResultSuccess = 1,
74     kResultUpdateDeferred = 9,  // When we ignore/defer updates due to policy.
75   };
76 
OmahaEventOmahaEvent77   OmahaEvent()
78       : type(kTypeUnknown),
79         result(kResultError),
80         error_code(ErrorCode::kError) {}
OmahaEventOmahaEvent81   explicit OmahaEvent(Type in_type)
82       : type(in_type),
83         result(kResultSuccess),
84         error_code(ErrorCode::kSuccess) {}
OmahaEventOmahaEvent85   OmahaEvent(Type in_type, Result in_result, ErrorCode in_error_code)
86       : type(in_type),
87         result(in_result),
88         error_code(in_error_code) {}
89 
90   Type type;
91   Result result;
92   ErrorCode error_code;
93 };
94 
95 class NoneType;
96 class OmahaRequestAction;
97 class OmahaRequestParams;
98 class PrefsInterface;
99 
100 // This struct is declared in the .cc file.
101 struct OmahaParserData;
102 
103 template<>
104 class ActionTraits<OmahaRequestAction> {
105  public:
106   // Takes parameters on the input pipe.
107   typedef NoneType InputObjectType;
108   // On UpdateCheck success, puts the Omaha response on output. Event
109   // requests do not have an output pipe.
110   typedef OmahaResponse OutputObjectType;
111 };
112 
113 class OmahaRequestAction : public Action<OmahaRequestAction>,
114                            public HttpFetcherDelegate {
115  public:
116   static const int kNeverPinged = -1;
117   static const int kPingTimeJump = -2;
118   // We choose this value of 10 as a heuristic for a work day in trying
119   // each URL, assuming we check roughly every 45 mins. This is a good time to
120   // wait - neither too long nor too little - so we don't give up the preferred
121   // URLs that appear earlier in list too quickly before moving on to the
122   // fallback ones.
123   static const int kDefaultMaxFailureCountPerUrl = 10;
124 
125   // These are the possible outcome upon checking whether we satisfied
126   // the wall-clock-based-wait.
127   enum WallClockWaitResult {
128     kWallClockWaitNotSatisfied,
129     kWallClockWaitDoneButUpdateCheckWaitRequired,
130     kWallClockWaitDoneAndUpdateCheckWaitNotRequired,
131   };
132 
133   // The ctor takes in all the parameters that will be used for making
134   // the request to Omaha. For some of them we have constants that
135   // should be used.
136   //
137   // Takes ownership of the passed in HttpFetcher. Useful for testing.
138   //
139   // Takes ownership of the passed in OmahaEvent. If |event| is null,
140   // this is an UpdateCheck request, otherwise it's an Event request.
141   // Event requests always succeed.
142   //
143   // A good calling pattern is:
144   // OmahaRequestAction(..., new OmahaEvent(...), new WhateverHttpFetcher);
145   // or
146   // OmahaRequestAction(..., nullptr, new WhateverHttpFetcher);
147   OmahaRequestAction(SystemState* system_state,
148                      OmahaEvent* event,
149                      std::unique_ptr<HttpFetcher> http_fetcher,
150                      bool ping_only);
151   ~OmahaRequestAction() override;
152   typedef ActionTraits<OmahaRequestAction>::InputObjectType InputObjectType;
153   typedef ActionTraits<OmahaRequestAction>::OutputObjectType OutputObjectType;
154   void PerformAction() override;
155   void TerminateProcessing() override;
156   void ActionCompleted(ErrorCode code) override;
157 
GetHTTPResponseCode()158   int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
159 
160   // Debugging/logging
StaticType()161   static std::string StaticType() { return "OmahaRequestAction"; }
Type()162   std::string Type() const override { return StaticType(); }
163 
164   // Delegate methods (see http_fetcher.h)
165   void ReceivedBytes(HttpFetcher *fetcher,
166                      const void* bytes, size_t length) override;
167 
168   void TransferComplete(HttpFetcher *fetcher, bool successful) override;
169 
170   // Returns true if this is an Event request, false if it's an UpdateCheck.
IsEvent()171   bool IsEvent() const { return event_.get() != nullptr; }
172 
173  private:
174   FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE);
175   FRIEND_TEST(OmahaRequestActionTest,
176               GetInstallDateWhenOOBECompletedWithInvalidDate);
177   FRIEND_TEST(OmahaRequestActionTest,
178               GetInstallDateWhenOOBECompletedWithValidDate);
179   FRIEND_TEST(OmahaRequestActionTest,
180               GetInstallDateWhenOOBECompletedDateChanges);
181 
182   // Enumeration used in PersistInstallDate().
183   enum InstallDateProvisioningSource {
184     kProvisionedFromOmahaResponse,
185     kProvisionedFromOOBEMarker,
186 
187     // kProvisionedMax is the count of the number of enums above. Add
188     // any new enums above this line only.
189     kProvisionedMax
190   };
191 
192   // Gets the install date, expressed as the number of PST8PDT
193   // calendar weeks since January 1st 2007, times seven. Returns -1 if
194   // unknown. See http://crbug.com/336838 for details about this value.
195   static int GetInstallDate(SystemState* system_state);
196 
197   // Parses the Omaha Response in |doc| and sets the
198   // |install_date_days| field of |output_object| to the value of the
199   // elapsed_days attribute of the daystart element. Returns True if
200   // the value was set, False if it wasn't found.
201   static bool ParseInstallDate(OmahaParserData* parser_data,
202                                OmahaResponse* output_object);
203 
204   // Returns True if the kPrefsInstallDateDays state variable is set,
205   // False otherwise.
206   static bool HasInstallDate(SystemState *system_state);
207 
208   // Writes |install_date_days| into the kPrefsInstallDateDays state
209   // variable and emits an UMA stat for the |source| used. Returns
210   // True if the value was written, False if an error occurred.
211   static bool PersistInstallDate(SystemState *system_state,
212                                  int install_date_days,
213                                  InstallDateProvisioningSource source);
214 
215   // Persist the new cohort* value received in the XML file in the |prefs_key|
216   // preference file. If the |new_value| is empty, the currently stored value
217   // will be deleted. Don't call this function with an empty |new_value| if the
218   // value was not set in the XML, since that would delete the stored value.
219   bool PersistCohortData(const std::string& prefs_key,
220                          const std::string& new_value);
221 
222   // If this is an update check request, initializes
223   // |ping_active_days_| and |ping_roll_call_days_| to values that may
224   // be sent as pings to Omaha.
225   void InitPingDays();
226 
227   // Based on the persistent preference store values, calculates the
228   // number of days since the last ping sent for |key|.
229   int CalculatePingDays(const std::string& key);
230 
231   // Returns whether we have "active_days" or "roll_call_days" ping values to
232   // send to Omaha and thus we should include them in the response.
233   bool ShouldPing() const;
234 
235   // Returns true if the download of a new update should be deferred.
236   // False if the update can be downloaded.
237   bool ShouldDeferDownload(OmahaResponse* output_object);
238 
239   // Returns true if the basic wall-clock-based waiting period has been
240   // satisfied based on the scattering policy setting. False otherwise.
241   // If true, it also indicates whether the additional update-check-count-based
242   // waiting period also needs to be satisfied before the download can begin.
243   WallClockWaitResult IsWallClockBasedWaitingSatisfied(
244       OmahaResponse* output_object);
245 
246   // Returns true if the update-check-count-based waiting period has been
247   // satisfied. False otherwise.
248   bool IsUpdateCheckCountBasedWaitingSatisfied();
249 
250   // Parses the response from Omaha that's available in |doc| using the other
251   // helper methods below and populates the |output_object| with the relevant
252   // values. Returns true if we should continue the parsing.  False otherwise,
253   // in which case it sets any error code using |completer|.
254   bool ParseResponse(OmahaParserData* parser_data,
255                      OmahaResponse* output_object,
256                      ScopedActionCompleter* completer);
257 
258   // Parses the status property in the given update_check_node and populates
259   // |output_object| if valid. Returns true if we should continue the parsing.
260   // False otherwise, in which case it sets any error code using |completer|.
261   bool ParseStatus(OmahaParserData* parser_data,
262                    OmahaResponse* output_object,
263                    ScopedActionCompleter* completer);
264 
265   // Parses the URL nodes in the given XML document and populates
266   // |output_object| if valid. Returns true if we should continue the parsing.
267   // False otherwise, in which case it sets any error code using |completer|.
268   bool ParseUrls(OmahaParserData* parser_data,
269                  OmahaResponse* output_object,
270                  ScopedActionCompleter* completer);
271 
272   // Parses the package node in the given XML document and populates
273   // |output_object| if valid. Returns true if we should continue the parsing.
274   // False otherwise, in which case it sets any error code using |completer|.
275   bool ParsePackage(OmahaParserData* parser_data,
276                     OmahaResponse* output_object,
277                     ScopedActionCompleter* completer);
278 
279   // Parses the other parameters in the given XML document and populates
280   // |output_object| if valid. Returns true if we should continue the parsing.
281   // False otherwise, in which case it sets any error code using |completer|.
282   bool ParseParams(OmahaParserData* parser_data,
283                    OmahaResponse* output_object,
284                    ScopedActionCompleter* completer);
285 
286   // Called by TransferComplete() to complete processing, either
287   // asynchronously after looking up resources via p2p or directly.
288   void CompleteProcessing();
289 
290   // Helper to asynchronously look up payload on the LAN.
291   void LookupPayloadViaP2P(const OmahaResponse& response);
292 
293   // Callback used by LookupPayloadViaP2P().
294   void OnLookupPayloadViaP2PCompleted(const std::string& url);
295 
296   // Returns true if the current update should be ignored.
297   bool ShouldIgnoreUpdate(const OmahaResponse& response) const;
298 
299   // Returns true if updates are allowed over the current type of connection.
300   // False otherwise.
301   bool IsUpdateAllowedOverCurrentConnection() const;
302 
303   // Global system context.
304   SystemState* system_state_;
305 
306   // Contains state that is relevant in the processing of the Omaha request.
307   OmahaRequestParams* params_;
308 
309   // Pointer to the OmahaEvent info. This is an UpdateCheck request if null.
310   std::unique_ptr<OmahaEvent> event_;
311 
312   // pointer to the HttpFetcher that does the http work
313   std::unique_ptr<HttpFetcher> http_fetcher_;
314 
315   // If true, only include the <ping> element in the request.
316   bool ping_only_;
317 
318   // Stores the response from the omaha server
319   brillo::Blob response_buffer_;
320 
321   // Initialized by InitPingDays to values that may be sent to Omaha
322   // as part of a ping message. Note that only positive values and -1
323   // are sent to Omaha.
324   int ping_active_days_;
325   int ping_roll_call_days_;
326 
327   DISALLOW_COPY_AND_ASSIGN(OmahaRequestAction);
328 };
329 
330 }  // namespace chromeos_update_engine
331 
332 #endif  // UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
333