| 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 |