OLD | NEW |
| (Empty) |
1 // Copyright 2011 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 #include "omaha/client/bundle_creator.h" | |
17 #include <atlsafe.h> | |
18 #include "omaha/base/debug.h" | |
19 #include "omaha/base/error.h" | |
20 #include "omaha/base/logging.h" | |
21 #include "omaha/base/safe_format.h" | |
22 #include "omaha/base/string.h" | |
23 #include "omaha/base/utils.h" | |
24 #include "omaha/base/vista_utils.h" | |
25 #include "omaha/client/client_utils.h" | |
26 #include "omaha/common/command_line.h" | |
27 #include "omaha/common/config_manager.h" | |
28 #include "omaha/common/const_goopdate.h" | |
29 #include "omaha/common/goopdate_utils.h" | |
30 #include "omaha/common/lang.h" | |
31 #include "omaha/common/update3_utils.h" | |
32 #include "goopdate/omaha3_idl.h" | |
33 | |
34 namespace omaha { | |
35 | |
36 namespace bundle_creator { | |
37 | |
38 namespace internal { | |
39 | |
40 // display_language and install_source can be empty. | |
41 HRESULT SetBundleProperties(const CString& display_language, | |
42 const CString& display_name, | |
43 const CString& install_source, | |
44 const CString& session_id, | |
45 IAppBundle* app_bundle) { | |
46 ASSERT1(!display_name.IsEmpty()); | |
47 ASSERT1(app_bundle); | |
48 | |
49 CString process_language = lang::GetLanguageForProcess(display_language); | |
50 HRESULT hr = app_bundle->put_displayLanguage(CComBSTR(process_language)); | |
51 if (FAILED(hr)) { | |
52 return hr; | |
53 } | |
54 | |
55 hr = app_bundle->put_displayName(CComBSTR(display_name)); | |
56 if (FAILED(hr)) { | |
57 return hr; | |
58 } | |
59 | |
60 hr = app_bundle->put_sessionId(CComBSTR(session_id)); | |
61 if (FAILED(hr)) { | |
62 return hr; | |
63 } | |
64 | |
65 if (!install_source.IsEmpty()) { | |
66 hr = app_bundle->put_installSource(CComBSTR(install_source)); | |
67 if (FAILED(hr)) { | |
68 return hr; | |
69 } | |
70 } | |
71 | |
72 return S_OK; | |
73 } | |
74 | |
75 // Do not use the apps member of extra_args. Those values are handled by | |
76 // PopulateAppSpecificData. | |
77 HRESULT PopulateCommonData(const CommandLineExtraArgs& extra_args, | |
78 bool is_eula_accepted, | |
79 IApp* app) { | |
80 ASSERT1(app); | |
81 | |
82 HRESULT hr = S_OK; | |
83 | |
84 // Set as soon as possible so pings can occur in error cases. | |
85 hr = app->put_isEulaAccepted(is_eula_accepted ? VARIANT_TRUE : VARIANT_FALSE); | |
86 if (FAILED(hr)) { | |
87 return hr; | |
88 } | |
89 | |
90 if (!extra_args.language.IsEmpty()) { | |
91 hr = app->put_language(CComBSTR(extra_args.language)); | |
92 if (FAILED(hr)) { | |
93 return hr; | |
94 } | |
95 } | |
96 | |
97 if (!IsEqualGUID(GUID_NULL, extra_args.installation_id)) { | |
98 hr = app->put_iid(CComBSTR(GuidToString(extra_args.installation_id))); | |
99 if (FAILED(hr)) { | |
100 return hr; | |
101 } | |
102 } | |
103 | |
104 if (!extra_args.brand_code.IsEmpty()) { | |
105 hr = app->put_brandCode(CComBSTR(extra_args.brand_code)); | |
106 if (FAILED(hr)) { | |
107 return hr; | |
108 } | |
109 } | |
110 | |
111 if (!extra_args.client_id.IsEmpty()) { | |
112 hr = app->put_clientId(CComBSTR(extra_args.client_id)); | |
113 if (FAILED(hr)) { | |
114 return hr; | |
115 } | |
116 } | |
117 | |
118 if (!extra_args.referral_id.IsEmpty()) { | |
119 hr = app->put_referralId(CComBSTR(extra_args.referral_id)); | |
120 if (FAILED(hr)) { | |
121 return hr; | |
122 } | |
123 } | |
124 | |
125 if (extra_args.browser_type != BROWSER_UNKNOWN) { | |
126 hr = app->put_browserType(extra_args.browser_type); | |
127 if (FAILED(hr)) { | |
128 return hr; | |
129 } | |
130 } | |
131 | |
132 hr = app->put_usageStatsEnable(extra_args.usage_stats_enable); | |
133 if (FAILED(hr)) { | |
134 return hr; | |
135 } | |
136 | |
137 return S_OK; | |
138 } | |
139 | |
140 HRESULT PopulateAppSpecificData(const CommandLineAppArgs& app_args, | |
141 IApp* app) { | |
142 ASSERT1(app); | |
143 | |
144 HRESULT hr = app->put_displayName(CComBSTR(app_args.app_name)); | |
145 if (FAILED(hr)) { | |
146 return hr; | |
147 } | |
148 | |
149 if (!app_args.ap.IsEmpty()) { | |
150 hr = app->put_ap(CComBSTR(app_args.ap)); | |
151 if (FAILED(hr)) { | |
152 return hr; | |
153 } | |
154 } | |
155 | |
156 if (!app_args.tt_token.IsEmpty()) { | |
157 hr = app->put_ttToken(CComBSTR(app_args.tt_token)); | |
158 if (FAILED(hr)) { | |
159 return hr; | |
160 } | |
161 } | |
162 | |
163 if (!app_args.encoded_installer_data.IsEmpty()) { | |
164 CString decoded_installer_data; | |
165 HRESULT hr = Utf8UrlEncodedStringToWideString( | |
166 app_args.encoded_installer_data, | |
167 &decoded_installer_data); | |
168 ASSERT(SUCCEEDED(hr), (_T("[Utf8UrlEncodedStringToWideString][0x%x]"), hr)); | |
169 if (FAILED(hr) || CString(decoded_installer_data).Trim().IsEmpty()) { | |
170 return GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS; | |
171 } | |
172 | |
173 hr = app->put_clientInstallData(CComBSTR(decoded_installer_data)); | |
174 if (FAILED(hr)) { | |
175 return hr; | |
176 } | |
177 } | |
178 | |
179 if (!app_args.install_data_index.IsEmpty()) { | |
180 hr = app->put_serverInstallDataIndex(CComBSTR(app_args.install_data_index)); | |
181 if (FAILED(hr)) { | |
182 return hr; | |
183 } | |
184 } | |
185 | |
186 if (!app_args.experiment_labels.IsEmpty()) { | |
187 hr = app->put_labels(CComBSTR(app_args.experiment_labels)); | |
188 if (FAILED(hr)) { | |
189 return hr; | |
190 } | |
191 } | |
192 | |
193 return S_OK; | |
194 } | |
195 | |
196 // Obtains tokens and passes them to put_altTokens when running as Local System. | |
197 // Does not do anything for per-user instances or when not run as Local System. | |
198 HRESULT SetAltTokens(bool is_machine, IAppBundle* app_bundle) { | |
199 ASSERT1(app_bundle); | |
200 | |
201 if (!is_machine) { | |
202 return S_OK; | |
203 } | |
204 | |
205 bool is_local_system = false; | |
206 HRESULT hr = IsSystemProcess(&is_local_system); | |
207 if (FAILED(hr)) { | |
208 return hr; | |
209 } | |
210 | |
211 if (!is_local_system) { | |
212 // Do not need alternate tokens. | |
213 return S_OK; | |
214 } | |
215 | |
216 CAccessToken primary_token; | |
217 hr = primary_token.GetProcessToken(TOKEN_ALL_ACCESS) ? | |
218 S_OK : HRESULTFromLastError(); | |
219 if (FAILED(hr)) { | |
220 CORE_LOG(LE, (_T("[GetProcessToken failed][0x%x]"), hr)); | |
221 return hr; | |
222 } | |
223 | |
224 CAccessToken impersonation_token; | |
225 HANDLE user_token = NULL; | |
226 | |
227 vista::GetLoggedOnUserToken(&user_token); | |
228 | |
229 if (user_token) { | |
230 impersonation_token.Attach(user_token); | |
231 } else if (!primary_token.CreateImpersonationToken(&impersonation_token)) { | |
232 hr = HRESULTFromLastError(); | |
233 CORE_LOG(LE, (_T("[CreateImpersonationToken failed][0x%x]"), hr)); | |
234 return hr; | |
235 } | |
236 | |
237 hr = app_bundle->put_altTokens( | |
238 reinterpret_cast<ULONG_PTR>(impersonation_token.GetHandle()), | |
239 reinterpret_cast<ULONG_PTR>(primary_token.GetHandle()), | |
240 ::GetCurrentProcessId()); | |
241 if (FAILED(hr)) { | |
242 CORE_LOG(LE, (_T("[put_altTokens failed][0x%x]"), hr)); | |
243 return hr; | |
244 } | |
245 | |
246 return S_OK; | |
247 } | |
248 | |
249 } // namespace internal | |
250 | |
251 HRESULT Create(bool is_machine, | |
252 const CString& display_language, | |
253 const CString& install_source, | |
254 const CString& session_id, | |
255 bool is_interactive, | |
256 IAppBundle** app_bundle) { | |
257 CORE_LOG(L2, (_T("[bundle_creator::Create]"))); | |
258 ASSERT1(app_bundle); | |
259 | |
260 CComPtr<IGoogleUpdate3> server; | |
261 HRESULT hr = update3_utils::CreateGoogleUpdate3Class(is_machine, &server); | |
262 if (FAILED(hr)) { | |
263 CORE_LOG(LE, (_T("[CreateGoogleUpdate3Class][0x%08x]"), hr)); | |
264 return hr; | |
265 } | |
266 | |
267 CComPtr<IAppBundle> app_bundle_ptr; | |
268 hr = update3_utils::CreateAppBundle(server, &app_bundle_ptr); | |
269 if (FAILED(hr)) { | |
270 CORE_LOG(LE, (_T("[CreateAppBundle failed][0x%08x]"), hr)); | |
271 return hr; | |
272 } | |
273 | |
274 hr = internal::SetBundleProperties(display_language, | |
275 client_utils::GetUpdateAllAppsBundleName(), | |
276 install_source, | |
277 session_id, | |
278 app_bundle_ptr); | |
279 if (FAILED(hr)) { | |
280 return hr; | |
281 } | |
282 | |
283 hr = internal::SetAltTokens(is_machine, app_bundle_ptr); | |
284 if (FAILED(hr)) { | |
285 return hr; | |
286 } | |
287 | |
288 hr = app_bundle_ptr->put_priority(is_interactive ? | |
289 INSTALL_PRIORITY_HIGH : | |
290 INSTALL_PRIORITY_LOW); | |
291 if (FAILED(hr)) { | |
292 return hr; | |
293 } | |
294 | |
295 hr = app_bundle_ptr->initialize(); | |
296 if (FAILED(hr)) { | |
297 return hr; | |
298 } | |
299 | |
300 *app_bundle = app_bundle_ptr.Detach(); | |
301 return S_OK; | |
302 } | |
303 | |
304 HRESULT CreateFromCommandLine(bool is_machine, | |
305 bool is_eula_accepted, | |
306 bool is_offline, | |
307 const CString& offline_directory, | |
308 const CommandLineExtraArgs& extra_args, | |
309 const CString& install_source, | |
310 const CString& session_id, | |
311 bool is_interactive, | |
312 IAppBundle** app_bundle) { | |
313 CORE_LOG(L2, (_T("[bundle_creator::CreateFromCommandLine]"))); | |
314 ASSERT1(app_bundle); | |
315 | |
316 CComPtr<IGoogleUpdate3> server; | |
317 HRESULT hr = update3_utils::CreateGoogleUpdate3Class(is_machine, &server); | |
318 if (FAILED(hr)) { | |
319 CORE_LOG(LE, (_T("[CreateGoogleUpdate3Class][0x%08x]"), hr)); | |
320 return hr; | |
321 } | |
322 | |
323 CComPtr<IAppBundle> app_bundle_ptr; | |
324 hr = update3_utils::CreateAppBundle(server, &app_bundle_ptr); | |
325 if (FAILED(hr)) { | |
326 CORE_LOG(LE, (_T("[CreateAppBundle failed][0x%08x]"), hr)); | |
327 return hr; | |
328 } | |
329 | |
330 hr = internal::SetBundleProperties(extra_args.language, | |
331 extra_args.bundle_name, | |
332 install_source, | |
333 session_id, | |
334 app_bundle_ptr); | |
335 if (FAILED(hr)) { | |
336 return hr; | |
337 } | |
338 | |
339 if (is_offline) { | |
340 CString offline_dir(offline_directory); | |
341 if (offline_dir.IsEmpty()) { | |
342 // For Omaha2 compatibility. | |
343 offline_dir = is_machine ? | |
344 ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() : | |
345 ConfigManager::Instance()->GetUserOfflineStorageDir(); | |
346 } | |
347 | |
348 hr = app_bundle_ptr->put_offlineDirectory(CComBSTR(offline_dir)); | |
349 if (FAILED(hr)) { | |
350 return hr; | |
351 } | |
352 } | |
353 | |
354 hr = internal::SetAltTokens(is_machine, app_bundle_ptr); | |
355 if (FAILED(hr)) { | |
356 return hr; | |
357 } | |
358 | |
359 hr = app_bundle_ptr->put_priority(is_interactive ? | |
360 INSTALL_PRIORITY_HIGH : | |
361 INSTALL_PRIORITY_LOW); | |
362 if (FAILED(hr)) { | |
363 return hr; | |
364 } | |
365 | |
366 hr = app_bundle_ptr->initialize(); | |
367 if (FAILED(hr)) { | |
368 return hr; | |
369 } | |
370 | |
371 for (size_t i = 0; i < extra_args.apps.size(); ++i) { | |
372 const CommandLineAppArgs& app_args(extra_args.apps[i]); | |
373 | |
374 const CComBSTR app_id(GuidToString(app_args.app_guid)); | |
375 | |
376 CComPtr<IApp> app; | |
377 hr = update3_utils::CreateApp(app_id, app_bundle_ptr, &app); | |
378 if (FAILED(hr)) { | |
379 return hr; | |
380 } | |
381 | |
382 hr = internal::PopulateCommonData(extra_args, is_eula_accepted, app); | |
383 if (FAILED(hr)) { | |
384 return hr; | |
385 } | |
386 | |
387 hr = internal::PopulateAppSpecificData(app_args, app); | |
388 if (FAILED(hr)) { | |
389 return hr; | |
390 } | |
391 } | |
392 | |
393 *app_bundle = app_bundle_ptr.Detach(); | |
394 return S_OK; | |
395 } | |
396 | |
397 HRESULT CreateForOnDemand(bool is_machine, | |
398 const CString& app_id, | |
399 const CString& install_source, | |
400 const CString& session_id, | |
401 HANDLE impersonation_token, | |
402 HANDLE primary_token, | |
403 IAppBundle** app_bundle) { | |
404 CORE_LOG(L2, (_T("[bundle_creator::CreateForOnDemand]"))); | |
405 ASSERT1(app_bundle); | |
406 | |
407 CComPtr<IGoogleUpdate3> server; | |
408 HRESULT hr = update3_utils::CreateGoogleUpdate3Class(is_machine, &server); | |
409 if (FAILED(hr)) { | |
410 CORE_LOG(LE, (_T("[CreateGoogleUpdate3Class failed][0x%x]"), hr)); | |
411 return hr; | |
412 } | |
413 | |
414 CComPtr<IAppBundle> app_bundle_ptr; | |
415 hr = update3_utils::CreateAppBundle(server, &app_bundle_ptr); | |
416 if (FAILED(hr)) { | |
417 CORE_LOG(LE, (_T("[CreateAppBundle failed][0x%x]"), hr)); | |
418 return hr; | |
419 } | |
420 | |
421 // ::CoSetProxyBlanket() settings are per proxy. For OnDemand, after | |
422 // unmarshaling the interface, we need to set the blanket on this new proxy. | |
423 // The proxy blanket on the IAppBundle interface are set explicitly only for | |
424 // OnDemand, because OnDemand is a unique case of being a COM server as well | |
425 // as a COM client. The default security settings set for the OnDemand COM | |
426 // server are more restrictive and rightly so, as compared to the settings | |
427 // that we set for a COM client such as our Omaha3 UI. Hence the need to | |
428 // explicitly set the proxy blanket settings and lower the security | |
429 // requirements only when calling out on this interface. | |
430 hr = update3_utils::SetProxyBlanketAllowImpersonate(app_bundle_ptr); | |
431 if (FAILED(hr)) { | |
432 return hr; | |
433 } | |
434 | |
435 if (is_machine) { | |
436 hr = app_bundle_ptr->put_altTokens( | |
437 reinterpret_cast<ULONG_PTR>(impersonation_token), | |
438 reinterpret_cast<ULONG_PTR>(primary_token), | |
439 ::GetCurrentProcessId()); | |
440 if (FAILED(hr)) { | |
441 CORE_LOG(LE, (_T("[put_altTokens failed][0x%x]"), hr)); | |
442 return hr; | |
443 } | |
444 } | |
445 | |
446 hr = internal::SetBundleProperties(CString(), | |
447 _T("On Demand Bundle"), | |
448 install_source, | |
449 session_id, | |
450 app_bundle_ptr); | |
451 if (FAILED(hr)) { | |
452 return hr; | |
453 } | |
454 | |
455 hr = app_bundle_ptr->initialize(); | |
456 if (FAILED(hr)) { | |
457 return hr; | |
458 } | |
459 | |
460 CComPtr<IApp> app; | |
461 hr = update3_utils::CreateInstalledApp(CComBSTR(app_id), | |
462 app_bundle_ptr, | |
463 &app); | |
464 if (FAILED(hr)) { | |
465 CORE_LOG(LE, (_T("[CreateInstalledApp failed][0x%x]"), hr)); | |
466 return hr; | |
467 } | |
468 | |
469 *app_bundle = app_bundle_ptr.Detach(); | |
470 return S_OK; | |
471 } | |
472 | |
473 } // namespace bundle_creator | |
474 | |
475 } // namespace omaha | |
OLD | NEW |