Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

662 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2001.
  5. //
  6. // sens.cpp
  7. //
  8. // Modele that implements a COM+ subscriber for use with SENS notifications.
  9. //
  10. // 10/9/2001 annah Created
  11. // Ported code from BITS sources. Removed SEH code,
  12. // changed methods that threw exceptions to return
  13. // error codes.
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #include "ausens.h"
  18. #include "tscompat.h"
  19. #include "service.h"
  20. static CLogonNotification *g_SensLogonNotification = NULL;
  21. HRESULT ActivateSensLogonNotification()
  22. {
  23. HRESULT hr = S_OK;
  24. // only activate once
  25. if ( g_SensLogonNotification )
  26. {
  27. DEBUGMSG("AUSENS Logon object was already created; reusing object.");
  28. return S_OK;
  29. }
  30. g_SensLogonNotification = new CLogonNotification();
  31. if (!g_SensLogonNotification)
  32. {
  33. DEBUGMSG("AUSENS Failed to alocate memory for CLogonNotification object.");
  34. return E_OUTOFMEMORY;
  35. }
  36. hr = g_SensLogonNotification->Initialize();
  37. if (FAILED(hr))
  38. {
  39. DEBUGMSG( "AUSENS notification activation failed." );
  40. }
  41. else
  42. {
  43. DEBUGMSG( "AUSENS notification activated" );
  44. }
  45. return hr;
  46. }
  47. HRESULT DeactivateSensLogonNotification()
  48. {
  49. if (!g_SensLogonNotification)
  50. {
  51. DEBUGMSG("AUSENS Logon object is not activated; ignoring call.");
  52. return S_OK;
  53. }
  54. delete g_SensLogonNotification;
  55. g_SensLogonNotification = NULL;
  56. DEBUGMSG( "AUSENS notification deactivated" );
  57. return S_OK;
  58. }
  59. //----------------------------------------------------------------------------
  60. // BSTR manipulation
  61. //----------------------------------------------------------------------------
  62. HRESULT AppendBSTR(BSTR *bstrDest, BSTR bstrAppend)
  63. {
  64. HRESULT hr = S_OK;
  65. BSTR bstrNew = NULL;
  66. if (bstrDest == NULL || *bstrDest == NULL)
  67. return E_INVALIDARG;
  68. if (bstrAppend == NULL)
  69. return S_OK;
  70. hr = VarBstrCat(*bstrDest, bstrAppend, &bstrNew);
  71. if (SUCCEEDED(hr))
  72. {
  73. SysFreeString(*bstrDest);
  74. *bstrDest = bstrNew;
  75. }
  76. return hr;
  77. }
  78. // Caller is responsible for freeing bstrOut
  79. HRESULT BSTRFromIID(IN REFIID riid, OUT BSTR *bstrOut)
  80. {
  81. HRESULT hr = S_OK;
  82. LPOLESTR lpszGUID = NULL;
  83. if (bstrOut == NULL)
  84. {
  85. hr = E_INVALIDARG;
  86. goto done;
  87. }
  88. hr = StringFromIID(riid, &lpszGUID);
  89. if (FAILED(hr))
  90. {
  91. DEBUGMSG("AUSENS Failed to extract GUID from string");
  92. goto done;
  93. }
  94. *bstrOut = SysAllocString(lpszGUID);
  95. if (*bstrOut == NULL)
  96. {
  97. hr = E_OUTOFMEMORY;
  98. goto done;
  99. }
  100. done:
  101. if (lpszGUID)
  102. {
  103. CoTaskMemFree(lpszGUID);
  104. }
  105. return hr;
  106. }
  107. HRESULT CBstrTable::Initialize()
  108. {
  109. HRESULT hr = S_OK;
  110. hr = BSTRFromIID(g_oLogonSubscription.MethodGuid, &m_bstrLogonMethodGuid);
  111. if (FAILED(hr))
  112. {
  113. goto done;
  114. }
  115. m_bstrLogonMethodName = SysAllocString(g_oLogonSubscription.pszMethodName);
  116. if (m_bstrLogonMethodName == NULL)
  117. {
  118. hr = E_OUTOFMEMORY;
  119. goto done;
  120. }
  121. m_bstrSubscriptionName = SysAllocString(SUBSCRIPTION_NAME_TEXT);
  122. if (m_bstrSubscriptionName == NULL)
  123. {
  124. hr = E_OUTOFMEMORY;
  125. goto done;
  126. }
  127. m_bstrSubscriptionDescription = SysAllocString(SUBSCRIPTION_DESCRIPTION_TEXT);
  128. if (m_bstrSubscriptionDescription == NULL)
  129. {
  130. hr = E_OUTOFMEMORY;
  131. goto done;
  132. }
  133. hr = BSTRFromIID(_uuidof(ISensLogon), &m_bstrSensLogonGuid);
  134. if (FAILED(hr))
  135. {
  136. goto done;
  137. }
  138. hr = BSTRFromIID(SENSGUID_EVENTCLASS_LOGON, &m_bstrSensEventClassGuid);
  139. if (FAILED(hr))
  140. {
  141. goto done;
  142. }
  143. done:
  144. return hr;
  145. }
  146. //----------------------------------------------------------------------------
  147. // Implementation for CLogonNotification methods
  148. //----------------------------------------------------------------------------
  149. HRESULT CLogonNotification::Initialize()
  150. {
  151. HRESULT hr = S_OK;
  152. SIZE_T cSubscriptions = 0;
  153. //
  154. // Create auxiliary object with BSTR names used for several actions
  155. //
  156. m_oBstrTable = new CBstrTable();
  157. if (!m_oBstrTable)
  158. {
  159. return E_OUTOFMEMORY;
  160. }
  161. hr = m_oBstrTable->Initialize();
  162. if (FAILED(hr))
  163. {
  164. DEBUGMSG("AUSENS Could not create auxiliary structure BstrTable");
  165. return hr;
  166. }
  167. //
  168. // Load the type library from SENS
  169. //
  170. hr = LoadTypeLibEx(L"SENS.DLL", REGKIND_NONE, &m_TypeLib);
  171. if (FAILED(hr))
  172. {
  173. DEBUGMSG("AUSENS Could not load type library from SENS DLL");
  174. goto done;
  175. }
  176. //
  177. // Get TypeInfo for ISensLogon from SENS typelib -- this will
  178. // simplify thing for us when implementing IDispatch methods
  179. //
  180. hr = m_TypeLib->GetTypeInfoOfGuid(__uuidof( ISensLogon ), &m_TypeInfo);
  181. if (FAILED(hr))
  182. {
  183. DEBUGMSG("AUSENS Could not get type info for ISensLogon.");
  184. goto done;
  185. }
  186. //
  187. // Grab an interface pointer of the EventSystem object
  188. //
  189. hr = CoCreateInstance(CLSID_CEventSystem, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IEventSystem, (void**)&m_EventSystem );
  190. if (FAILED(hr))
  191. {
  192. DEBUGMSG("AUSENS Failed to create EventSytem instance for Sens subscription. Error is %x.", hr);
  193. goto done;
  194. }
  195. //
  196. // Subscribe for the Logon notifications
  197. //
  198. DEBUGMSG("AUSENS Subscribing method '%S' with SENS (%S)", m_oBstrTable->m_bstrLogonMethodName, m_oBstrTable->m_bstrLogonMethodGuid);
  199. hr = SubscribeMethod(m_oBstrTable->m_bstrLogonMethodName, m_oBstrTable->m_bstrLogonMethodGuid);
  200. if (FAILED(hr))
  201. {
  202. DEBUGMSG("AUSENS Subscription for method failed.");
  203. goto done;
  204. }
  205. m_fSubscribed = TRUE;
  206. done:
  207. return hr;
  208. }
  209. HRESULT CLogonNotification::UnsubscribeAllMethods()
  210. {
  211. HRESULT hr = S_OK;
  212. BSTR bstrQuery = NULL;
  213. BSTR bstrAux = NULL;
  214. int ErrorIndex;
  215. DEBUGMSG("AUSENS Unsubscribing all methods");
  216. //
  217. // The query should be a string in the following format:
  218. // EventClassID == {D5978630-5B9F-11D1-8DD2-00AA004ABD5E} and SubscriptioniD == {XXXXXXX-5B9F-11D1-8DD2-00AA004ABD5E}
  219. //
  220. bstrQuery = SysAllocString(L"EventClassID == ");
  221. if (bstrQuery == NULL)
  222. {
  223. hr = E_OUTOFMEMORY;
  224. goto done;
  225. }
  226. bstrAux = SysAllocString(L" and SubscriptionID == ");
  227. if (bstrAux == NULL)
  228. {
  229. hr = E_OUTOFMEMORY;
  230. goto done;
  231. }
  232. hr = AppendBSTR(&bstrQuery, m_oBstrTable->m_bstrSensLogonGuid);
  233. if (FAILED(hr))
  234. {
  235. DEBUGMSG("AUSENS Failed to append BSTR string");
  236. goto done;
  237. }
  238. hr = AppendBSTR(&bstrQuery, bstrAux);
  239. if (FAILED(hr))
  240. {
  241. DEBUGMSG("AUSENS Failed to append BSTR string");
  242. goto done;
  243. }
  244. hr = AppendBSTR(&bstrQuery, m_oBstrTable->m_bstrLogonMethodGuid);
  245. if (FAILED(hr))
  246. {
  247. DEBUGMSG("AUSENS Failed to append BSTR string");
  248. goto done;
  249. }
  250. if (bstrQuery != NULL)
  251. {
  252. // Remove subscription for all ISensLogon subscription that were added for this WU component
  253. DEBUGMSG("AUSENS remove subscription query: %S", bstrQuery);
  254. hr = m_EventSystem->Remove( PROGID_EventSubscription, bstrQuery, &ErrorIndex );
  255. if (FAILED(hr))
  256. {
  257. DEBUGMSG("AUSENS Failed to remove AU Subscription from COM Event System");
  258. goto done;
  259. }
  260. m_fSubscribed = FALSE;
  261. }
  262. else
  263. {
  264. hr = E_OUTOFMEMORY;
  265. goto done;
  266. }
  267. done:
  268. SafeFreeBSTR(bstrQuery);
  269. SafeFreeBSTR(bstrAux);
  270. return hr;
  271. }
  272. HRESULT CLogonNotification::SubscribeMethod(const BSTR bstrMethodName, const BSTR bstrMethodGuid)
  273. {
  274. HRESULT hr = S_OK;
  275. IEventSubscription *pEventSubscription = NULL;
  276. //
  277. // Create an instance of EventSubscription
  278. //
  279. hr = CoCreateInstance(CLSID_CEventSubscription, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IEventSubscription, (void**)&pEventSubscription);
  280. if (FAILED(hr))
  281. {
  282. DEBUGMSG("AUSENS Failed to instanciate EventSubscription object");
  283. goto done;
  284. }
  285. //
  286. // Subscribe the method
  287. //
  288. hr = pEventSubscription->put_EventClassID(m_oBstrTable->m_bstrSensEventClassGuid);
  289. if (FAILED(hr))
  290. {
  291. DEBUGMSG("AUSENS Failed to set EventClassID during method subscription");
  292. goto done;
  293. }
  294. hr = pEventSubscription->put_SubscriberInterface(this);
  295. if (FAILED(hr))
  296. {
  297. DEBUGMSG("AUSENS Failed to set EventClassID during method subscription");
  298. goto done;
  299. }
  300. hr = pEventSubscription->put_SubscriptionName(m_oBstrTable->m_bstrSubscriptionName);
  301. if (FAILED(hr))
  302. {
  303. DEBUGMSG("AUSENS Failed to set EventClassID during method subscription");
  304. goto done;
  305. }
  306. hr = pEventSubscription->put_Description(m_oBstrTable->m_bstrSubscriptionDescription);
  307. if (FAILED(hr))
  308. {
  309. DEBUGMSG("AUSENS Failed to set subscription method during method subscription");
  310. goto done;
  311. }
  312. hr = pEventSubscription->put_Enabled(TRUE);
  313. if (FAILED(hr))
  314. {
  315. DEBUGMSG("AUSENS Failed to set enabled flag during method subscription");
  316. goto done;
  317. }
  318. hr = pEventSubscription->put_MethodName(bstrMethodName);
  319. if (FAILED(hr))
  320. {
  321. DEBUGMSG("AUSENS Failed to set MethodName during method subscription");
  322. goto done;
  323. }
  324. hr = pEventSubscription->put_SubscriptionID(bstrMethodGuid);
  325. if (FAILED(hr))
  326. {
  327. DEBUGMSG("AUSENS Failed to set SubscriptionID during method subscription");
  328. goto done;
  329. }
  330. hr = m_EventSystem->Store(PROGID_EventSubscription, pEventSubscription);
  331. if (FAILED(hr))
  332. {
  333. DEBUGMSG("AUSENS Failed to store Event Subscription in the Event System");
  334. goto done;
  335. }
  336. done:
  337. SafeRelease(pEventSubscription);
  338. return hr;
  339. }
  340. void CLogonNotification::Cleanup()
  341. {
  342. __try
  343. {
  344. if (m_EventSystem)
  345. {
  346. if (m_fSubscribed)
  347. {
  348. UnsubscribeAllMethods();
  349. }
  350. SafeRelease(m_EventSystem);
  351. }
  352. SafeRelease(m_TypeInfo);
  353. SafeRelease(m_TypeLib);
  354. }
  355. __except(EXCEPTION_EXECUTE_HANDLER)
  356. {
  357. DEBUGMSG("AUSENS Cleanup raised and execution exception that was trapped.");
  358. }
  359. if (m_oBstrTable)
  360. {
  361. delete m_oBstrTable;
  362. m_oBstrTable = NULL;
  363. }
  364. }
  365. HRESULT CLogonNotification::CheckLocalSystem()
  366. {
  367. HRESULT hr = E_FAIL;
  368. PSID pLocalSid = NULL;
  369. HANDLE hToken = NULL;
  370. SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY;
  371. BOOL fRet = FALSE;
  372. BOOL fIsLocalSystem = FALSE;
  373. fRet = AllocateAndInitializeSid(
  374. &IDAuthorityNT,
  375. 1,
  376. SECURITY_LOCAL_SYSTEM_RID,
  377. 0,0,0,0,0,0,0,
  378. &pLocalSid );
  379. if (fRet == FALSE)
  380. {
  381. hr = HRESULT_FROM_WIN32(GetLastError());
  382. DEBUGMSG("AUSENS AllocateAndInitializeSid failed with error %x", hr);
  383. goto done;
  384. }
  385. if (FAILED(hr = CoImpersonateClient()))
  386. {
  387. DEBUGMSG("AUSENS Failed to impersonate client", hr);
  388. hr = E_ACCESSDENIED;
  389. goto done;
  390. }
  391. fRet = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken);
  392. if (fRet == FALSE)
  393. {
  394. hr = HRESULT_FROM_WIN32(GetLastError());
  395. DEBUGMSG("AUSENS Failed to OpenProcessToken");
  396. goto done;
  397. }
  398. if (FAILED(CoRevertToSelf()))
  399. {
  400. AUASSERT(FALSE); //should never be there
  401. hr = E_ACCESSDENIED;
  402. goto done;
  403. }
  404. fRet = CheckTokenMembership(hToken, pLocalSid, &fIsLocalSystem);
  405. if (fRet == FALSE)
  406. {
  407. hr = HRESULT_FROM_WIN32(GetLastError());
  408. DEBUGMSG("AUSENS fail to Check token membership with error %x", hr);
  409. goto done;
  410. }
  411. if (fIsLocalSystem)
  412. {
  413. hr = S_OK;
  414. }
  415. else
  416. {
  417. hr = E_ACCESSDENIED;
  418. DEBUGMSG("AUSENS SECURITY CHECK Current thread is not running as LocalSystem!!");
  419. }
  420. done:
  421. if (hToken != NULL)
  422. CloseHandle(hToken);
  423. if (pLocalSid != NULL)
  424. FreeSid(pLocalSid);
  425. return hr;
  426. }
  427. STDMETHODIMP CLogonNotification::Logon( BSTR UserName )
  428. {
  429. DEBUGMSG("AUSENS logon notification for %S", (WCHAR*)UserName );
  430. DEBUGMSG("AUSENS Forcing the rebuilt of the cachesessions array");
  431. //
  432. // fix for security bug 563054 -- annah
  433. //
  434. // The Logon() method is called by the COM+ Event System to notify us of a logon event
  435. // We expose the ISensLogon interface but don't want anybody calling us
  436. // that is not the COM+ Event System.
  437. //
  438. // The COM+ Event System service runs as Local System in the netsvcs svchost group.
  439. // We will check if the caller is really the Event System by checking for
  440. // the Local System account.
  441. //
  442. HRESULT hr = CheckLocalSystem();
  443. if (FAILED(hr))
  444. {
  445. DEBUGMSG("AUSENS CheckLocalSystem failed with error %x. Will not trigger logon notification", hr);
  446. goto done;
  447. }
  448. //
  449. // One big problem of the code below is that although we're validating that
  450. // there are admins on the machine who are valid users for AU, it could be the
  451. // same that was already there, because we don't have a reliable way of receiving
  452. // logoff notifications. So we will raise the NEW_ADMIN event here, and
  453. // we will block the cretiion of a new client if we detect that there's a
  454. // a client still running.
  455. //
  456. gAdminSessions.RebuildSessionCache();
  457. if (gAdminSessions.CSessions() > 0)
  458. {
  459. DEBUGMSG("AU SENS Logon: There are admins in the admin cache, raising NEW_ADMIN event (it could be a false alarm)");
  460. SetActiveAdminSessionEvent();
  461. }
  462. #if DBG
  463. gAdminSessions.m_DumpSessions();
  464. #endif
  465. done:
  466. return S_OK;
  467. }
  468. STDMETHODIMP CLogonNotification::Logoff( BSTR UserName )
  469. {
  470. DEBUGMSG( "AUSENS logoff notification for %S", (WCHAR*)UserName );
  471. // do nothing
  472. #if DBG
  473. gAdminSessions.m_DumpSessions();
  474. #endif
  475. return S_OK;
  476. }
  477. STDMETHODIMP CLogonNotification::QueryInterface(REFIID iid, void** ppvObject)
  478. {
  479. HRESULT hr = S_OK;
  480. *ppvObject = NULL;
  481. if ((iid == IID_IUnknown) || (iid == _uuidof(IDispatch)) || (iid == _uuidof(ISensLogon)))
  482. {
  483. *ppvObject = static_cast<ISensLogon *> (this);
  484. (static_cast<IUnknown *>(*ppvObject))->AddRef();
  485. }
  486. else
  487. {
  488. hr = E_NOINTERFACE;
  489. }
  490. return hr;
  491. }
  492. STDMETHODIMP CLogonNotification::GetIDsOfNames(REFIID, OLECHAR ** rgszNames, unsigned int cNames, LCID, DISPID *rgDispId )
  493. {
  494. return m_TypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
  495. }
  496. STDMETHODIMP CLogonNotification::GetTypeInfo(unsigned int iTInfo, LCID, ITypeInfo **ppTInfo )
  497. {
  498. if ( iTInfo != 0 )
  499. return DISP_E_BADINDEX;
  500. *ppTInfo = m_TypeInfo;
  501. m_TypeInfo->AddRef();
  502. return S_OK;
  503. }
  504. STDMETHODIMP CLogonNotification::GetTypeInfoCount(unsigned int *pctinfo)
  505. {
  506. *pctinfo = 1;
  507. return S_OK;
  508. }
  509. STDMETHODIMP CLogonNotification::Invoke(
  510. DISPID dispID,
  511. REFIID riid,
  512. LCID,
  513. WORD wFlags,
  514. DISPPARAMS *pDispParams,
  515. VARIANT *pvarResult,
  516. EXCEPINFO *pExcepInfo,
  517. unsigned int *puArgErr )
  518. {
  519. if (riid != IID_NULL)
  520. {
  521. return DISP_E_UNKNOWNINTERFACE;
  522. }
  523. return m_TypeInfo->Invoke(
  524. (IDispatch*) this,
  525. dispID,
  526. wFlags,
  527. pDispParams,
  528. pvarResult,
  529. pExcepInfo,
  530. puArgErr
  531. );
  532. }
  533. STDMETHODIMP CLogonNotification::DisplayLock( BSTR UserName )
  534. {
  535. return S_OK;
  536. }
  537. STDMETHODIMP CLogonNotification::DisplayUnlock( BSTR UserName )
  538. {
  539. return S_OK;
  540. }
  541. STDMETHODIMP CLogonNotification::StartScreenSaver( BSTR UserName )
  542. {
  543. return S_OK;
  544. }
  545. STDMETHODIMP CLogonNotification::StopScreenSaver( BSTR UserName )
  546. {
  547. return S_OK;
  548. }
  549. STDMETHODIMP CLogonNotification::StartShell( BSTR UserName )
  550. {
  551. return S_OK;
  552. }