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