OLD | NEW |
| (Empty) |
1 // Copyright 2010 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 // TODO(omaha3): This really is a client. Where should it and similar code live? | |
17 | |
18 #ifndef OMAHA_GOOPDATE_ONDEMAND_H_ | |
19 #define OMAHA_GOOPDATE_ONDEMAND_H_ | |
20 | |
21 #include <atlbase.h> | |
22 #include <oaidl.h> | |
23 #include <oleauto.h> | |
24 #include "base/basictypes.h" | |
25 #include "base/debug.h" | |
26 #include "base/scoped_ptr.h" | |
27 #include "omaha/base/atlregmapex.h" | |
28 #include "omaha/base/constants.h" | |
29 #include "omaha/base/preprocessor_fun.h" | |
30 #include "omaha/base/scope_guard.h" | |
31 #include "omaha/base/thread_pool_callback.h" | |
32 #include "omaha/base/utils.h" | |
33 #include "omaha/common/const_goopdate.h" | |
34 #include "omaha/goopdate/com_proxy.h" | |
35 #include "omaha/goopdate/elevation_moniker_resource.h" | |
36 #include "goopdate/omaha3_idl.h" | |
37 // TODO(omaha3): Worker is convenient, but it is very odd to include part of the | |
38 // Omaha 3 COM server in one of its clients. | |
39 #include "omaha/goopdate/goopdate.h" | |
40 | |
41 namespace omaha { | |
42 | |
43 namespace internal { | |
44 | |
45 struct OnDemandParameters { | |
46 public: | |
47 OnDemandParameters(const CString& guid, | |
48 DWORD job_observer_cookie, | |
49 bool is_check_only, | |
50 const CString& sess_id, | |
51 HANDLE caller_impersonation_token, | |
52 HANDLE caller_primary_token) | |
53 : app_id(guid), | |
54 job_observer_git_cookie(job_observer_cookie), | |
55 is_update_check_only(is_check_only), | |
56 session_id(sess_id), | |
57 impersonation_token(caller_impersonation_token), | |
58 primary_token(caller_primary_token) { | |
59 ASSERT1(guid.GetLength() > 0); | |
60 ASSERT1(IsGuid(session_id)); | |
61 ASSERT1(job_observer_cookie); | |
62 } | |
63 | |
64 CString app_id; | |
65 DWORD job_observer_git_cookie; | |
66 bool is_update_check_only; | |
67 CString session_id; | |
68 HANDLE impersonation_token; | |
69 HANDLE primary_token; | |
70 }; | |
71 | |
72 HRESULT DoOnDemand(bool is_machine, | |
73 OnDemandParameters on_demand_params); | |
74 | |
75 } // namespace internal | |
76 | |
77 #pragma warning(push) | |
78 | |
79 // Construction of local static object is not thread-safe | |
80 #pragma warning(disable:4640) | |
81 | |
82 template <typename T> | |
83 class ATL_NO_VTABLE OnDemand | |
84 : public CComObjectRootEx<CComObjectThreadModel>, | |
85 public CComCoClass<OnDemand<T> >, | |
86 public IGoogleUpdate, | |
87 public StdMarshalInfo { | |
88 public: | |
89 // IGoogleUpdate::CheckForUpdate(). | |
90 STDMETHOD(CheckForUpdate)(const WCHAR* guid, IJobObserver* observer) { | |
91 return DoOnDemandInternalAsync(guid, observer, true); | |
92 } | |
93 | |
94 // IGoogleUpdate::Update(). | |
95 STDMETHOD(Update)(const WCHAR* guid, IJobObserver* observer) { | |
96 // Verify that the caller is an administrator for the machine case. | |
97 if (T::is_machine() && | |
98 !UserRights::TokenIsAdmin(impersonation_token_.GetHandle())) { | |
99 CORE_LOG(LE, (_T("[User is not an admin]"))); | |
100 return E_ACCESSDENIED; | |
101 } | |
102 | |
103 return DoOnDemandInternalAsync(guid, observer, false); | |
104 } | |
105 | |
106 HRESULT FinalConstruct() { | |
107 CORE_LOG(L2, (_T("[OnDemand::FinalConstruct]"))); | |
108 | |
109 if (!T::is_machine()) { | |
110 return S_OK; | |
111 } | |
112 | |
113 HRESULT hr = UserRights::GetCallerToken(&impersonation_token_); | |
114 if (FAILED(hr)) { | |
115 CORE_LOG(LE, (_T("[GetCallerToken failed][0x%x]"), hr)); | |
116 return hr; | |
117 } | |
118 | |
119 if (!impersonation_token_.CreatePrimaryToken(&primary_token_)) { | |
120 HRESULT hr = HRESULTFromLastError(); | |
121 CORE_LOG(LE, (_T("[CreatePrimaryToken failed][%d]"), hr)); | |
122 return hr; | |
123 } | |
124 | |
125 return S_OK; | |
126 } | |
127 | |
128 protected: | |
129 OnDemand() : StdMarshalInfo(T::is_machine()) { | |
130 CORE_LOG(L2, (_T("[OnDemand::OnDemand]"))); | |
131 } | |
132 | |
133 virtual ~OnDemand() { | |
134 CORE_LOG(L2, (_T("[OnDemand::~OnDemand]"))); | |
135 } | |
136 | |
137 void FinalRelease() { | |
138 CORE_LOG(L2, (_T("[OnDemand::FinalRelease]"))); | |
139 } | |
140 | |
141 HRESULT DoOnDemandInternalAsync(const WCHAR* guid, | |
142 IJobObserver* observer, | |
143 bool is_update_check_only) { | |
144 CORE_LOG(L2, (_T("[DoOnDemandInternalAsync][%s][%d]"), | |
145 guid, is_update_check_only)); | |
146 | |
147 CComGITPtr<IJobObserver> job_observer_git; | |
148 HRESULT hr = job_observer_git.Attach(observer); | |
149 if (FAILED(hr)) { | |
150 CORE_LOG(LE, (_T("[job_observer_git.Attach failed][0x%x]"), hr)); | |
151 return hr; | |
152 } | |
153 | |
154 CAccessToken dup_impersonation_token; | |
155 CAccessToken dup_primary_token; | |
156 if (T::is_machine()) { | |
157 hr = DuplicateTokenIntoCurrentProcess(::GetCurrentProcess(), | |
158 impersonation_token_.GetHandle(), | |
159 &dup_impersonation_token); | |
160 if (FAILED(hr)) { | |
161 CORE_LOG(LE, (_T("[Failed to duplicate impersonation token][0x%x]"), | |
162 hr)); | |
163 return hr; | |
164 } | |
165 | |
166 hr = DuplicateTokenIntoCurrentProcess(::GetCurrentProcess(), | |
167 primary_token_.GetHandle(), | |
168 &dup_primary_token); | |
169 if (FAILED(hr)) { | |
170 CORE_LOG(LE, (_T("[Failed to duplicate primary token][0x%x]"), hr)); | |
171 return hr; | |
172 } | |
173 } | |
174 | |
175 if (session_id_.IsEmpty()) { | |
176 VERIFY1(SUCCEEDED(GetGuid(&session_id_))); | |
177 } | |
178 | |
179 // Create a thread pool work item for deferred execution of the on demand | |
180 // check. The thread pool owns this call back object. The thread owns the | |
181 // impersonation and primary tokens. | |
182 typedef StaticThreadPoolCallBack1<internal::OnDemandParameters> Callback; | |
183 scoped_ptr<Callback> callback( | |
184 new Callback(&OnDemand::DoOnDemandInternal, | |
185 internal::OnDemandParameters( | |
186 guid, | |
187 job_observer_git.Detach(), | |
188 is_update_check_only, | |
189 session_id_, | |
190 dup_impersonation_token.GetHandle(), | |
191 dup_primary_token.GetHandle()))); | |
192 | |
193 hr = Goopdate::Instance().QueueUserWorkItem(callback.get(), | |
194 WT_EXECUTELONGFUNCTION); | |
195 if (FAILED(hr)) { | |
196 CORE_LOG(LE, (_T("[QueueUserWorkItem failed][0x%x]"), hr)); | |
197 return hr; | |
198 } | |
199 | |
200 if (T::is_machine()) { | |
201 dup_impersonation_token.Detach(); | |
202 dup_primary_token.Detach(); | |
203 } | |
204 | |
205 callback.release(); | |
206 | |
207 return S_OK; | |
208 } | |
209 | |
210 static void DoOnDemandInternal( | |
211 internal::OnDemandParameters on_demand_params) { | |
212 CORE_LOG(L2, (_T("[DoOnDemandInternal][%d]"), | |
213 on_demand_params.is_update_check_only)); | |
214 _pAtlModule->Lock(); | |
215 ON_SCOPE_EXIT_OBJ(*_pAtlModule, &CAtlModule::Unlock); | |
216 | |
217 scoped_handle impersonation_token(on_demand_params.impersonation_token); | |
218 scoped_handle primary_token(on_demand_params.primary_token); | |
219 | |
220 scoped_co_init init_com_apt(COINIT_APARTMENTTHREADED); | |
221 HRESULT hr = init_com_apt.hresult(); | |
222 if (FAILED(hr)) { | |
223 CORE_LOG(LE, (_T("[init_com_apt failed][0x%x]"), hr)); | |
224 return; | |
225 } | |
226 | |
227 hr = internal::DoOnDemand(T::is_machine(), on_demand_params); | |
228 if (FAILED(hr)) { | |
229 CORE_LOG(LE, (_T("[DoOnDemand failed][0x%x]"), hr)); | |
230 return; | |
231 } | |
232 } | |
233 | |
234 DECLARE_NOT_AGGREGATABLE(OnDemand) | |
235 DECLARE_REGISTRY_RESOURCEID_EX(T::registry_res_id()) | |
236 | |
237 BEGIN_REGISTRY_MAP() | |
238 REGMAP_ENTRY(_T("HKROOT"), T::hk_root()) | |
239 REGMAP_ENTRY(_T("VERSION"), _T("1.0")) | |
240 REGMAP_ENTRY(_T("PROGID"), T::prog_id()) | |
241 REGMAP_ENTRY(_T("DESCRIPTION"), _T("Google Update Legacy On Demand")) | |
242 REGMAP_ENTRY(_T("CLSID"), T::class_id()) | |
243 REGMAP_MODULE2(_T("MODULE"), kOmahaOnDemandFileName) | |
244 REGMAP_ENTRY(_T("ICONRESID"), PP_STRINGIZE(IDI_ELEVATION_MONIKER_ICON)) | |
245 REGMAP_ENTRY(_T("STRINGRESID"), | |
246 PP_STRINGIZE(IDS_ELEVATION_MONIKER_DISPLAYNAME)) | |
247 END_REGISTRY_MAP() | |
248 | |
249 BEGIN_COM_MAP(OnDemand) | |
250 COM_INTERFACE_ENTRY(IGoogleUpdate) | |
251 COM_INTERFACE_ENTRY(IStdMarshalInfo) | |
252 END_COM_MAP() | |
253 | |
254 private: | |
255 CAccessToken impersonation_token_; | |
256 CAccessToken primary_token_; | |
257 CString session_id_; | |
258 | |
259 DISALLOW_COPY_AND_ASSIGN(OnDemand); | |
260 }; | |
261 | |
262 struct OnDemandModeUser { | |
263 static bool is_machine() { return false; } | |
264 static const TCHAR* const prog_id() { return kProgIDOnDemandUser; } | |
265 static GUID class_id() { return __uuidof(OnDemandUserAppsClass); } | |
266 static UINT registry_res_id() { return IDR_LOCAL_SERVER_RGS; } | |
267 static const TCHAR* const hk_root() { return _T("HKCU"); } | |
268 }; | |
269 | |
270 struct OnDemandModeMachineFallback { | |
271 static bool is_machine() { return true; } | |
272 static const TCHAR* const prog_id() { return kProgIDOnDemandMachineFallback; } | |
273 static GUID class_id() { return __uuidof(OnDemandMachineAppsFallbackClass); } | |
274 static UINT registry_res_id() { return IDR_LOCAL_SERVER_ELEVATION_RGS; } | |
275 static const TCHAR* const hk_root() { return _T("HKLM"); } | |
276 }; | |
277 | |
278 struct OnDemandModeService { | |
279 static bool is_machine() { return true; } | |
280 static const TCHAR* const prog_id() { return kProgIDOnDemandSvc; } | |
281 static GUID class_id() { return __uuidof(OnDemandMachineAppsServiceClass); } | |
282 static UINT registry_res_id() { return IDR_LOCAL_SERVICE_RGS; } | |
283 static const TCHAR* const hk_root() { return _T("HKLM"); } | |
284 }; | |
285 | |
286 typedef OnDemand<OnDemandModeUser> OnDemandUser; | |
287 typedef OnDemand<OnDemandModeMachineFallback> OnDemandMachineFallback; | |
288 typedef OnDemand<OnDemandModeService> OnDemandService; | |
289 | |
290 #pragma warning(pop) | |
291 | |
292 } // namespace omaha | |
293 | |
294 #endif // OMAHA_GOOPDATE_ONDEMAND_H_ | |
OLD | NEW |