Leaked source code of windows server 2003
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.

664 lines
21 KiB

  1. #include "precomp.h"
  2. #include <stdio.h>
  3. #include <wbemutil.h>
  4. #include <wbemcomn.h>
  5. #include <GroupsForUser.h>
  6. #include "evtlog.h"
  7. #include <GenUtils.h>
  8. #include <comdef.h>
  9. #include <Sddl.h>
  10. #undef _ASSERT
  11. #include <atlbase.h>
  12. #define EVENTLOG_PROPNAME_SERVER L"UNCServerName"
  13. #define EVENTLOG_PROPNAME_SOURCE L"SourceName"
  14. #define EVENTLOG_PROPNAME_EVENTID L"EventID"
  15. #define EVENTLOG_PROPNAME_TYPE L"EventType"
  16. #define EVENTLOG_PROPNAME_CATEGORY L"Category"
  17. #define EVENTLOG_PROPNAME_NUMSTRINGS L"NumberOfInsertionStrings"
  18. #define EVENTLOG_PROPNAME_STRINGS L"InsertionStringTemplates"
  19. #define EVENTLOG_PROPNAME_CREATORSID L"CreatorSid"
  20. #define EVENTLOG_PROPNAME_DATANAME L"NameOfRawDataProperty"
  21. #define EVENTLOG_PROPNAME_SIDNAME L"NameOfUserSIDProperty"
  22. HRESULT STDMETHODCALLTYPE CEventLogConsumer::XProvider::FindConsumer(
  23. IWbemClassObject* pLogicalConsumer,
  24. IWbemUnboundObjectSink** ppConsumer)
  25. {
  26. CEventLogSink* pSink = new CEventLogSink(m_pObject->m_pControl);
  27. if(pSink == NULL)
  28. return WBEM_E_OUT_OF_MEMORY;
  29. HRESULT hres = pSink->Initialize(pLogicalConsumer);
  30. if(FAILED(hres))
  31. {
  32. delete pSink;
  33. *ppConsumer = NULL;
  34. return hres;
  35. }
  36. else return pSink->QueryInterface(IID_IWbemUnboundObjectSink,
  37. (void**)ppConsumer);
  38. }
  39. void* CEventLogConsumer::GetInterface(REFIID riid)
  40. {
  41. if(riid == IID_IWbemEventConsumerProvider)
  42. return &m_XProvider;
  43. else return NULL;
  44. }
  45. CEventLogSink::~CEventLogSink()
  46. {
  47. if(m_hEventLog)
  48. DeregisterEventSource(m_hEventLog);
  49. if(m_aTemplates)
  50. delete [] m_aTemplates;
  51. if(m_pSidCreator)
  52. delete [] m_pSidCreator;
  53. }
  54. HRESULT CEventLogSink::Initialize(IWbemClassObject* pLogicalConsumer)
  55. {
  56. // Get the information
  57. // ===================
  58. HRESULT hres = WBEM_S_NO_ERROR;
  59. CComVariant v;
  60. // Get the server and source
  61. // =========================
  62. WString wsServer;
  63. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SERVER, 0, &v, NULL, NULL);
  64. if(FAILED(hres)) return hres;
  65. if(V_VT(&v) == VT_BSTR)
  66. wsServer = V_BSTR(&v);
  67. VariantClear(&v);
  68. WString wsSource;
  69. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SOURCE, 0, &v, NULL, NULL);
  70. if(SUCCEEDED(hres) && (V_VT(&v) == VT_BSTR))
  71. wsSource = V_BSTR(&v);
  72. VariantClear(&v);
  73. m_hEventLog = RegisterEventSourceW(
  74. ( (wsServer.Length() == 0) ? NULL : (LPCWSTR)wsServer),
  75. wsSource);
  76. if(m_hEventLog == NULL)
  77. {
  78. ERRORTRACE((LOG_ESS, "Unable to register event source '%S' on server "
  79. "'%S'. Error code: %X\n", (LPCWSTR)wsSource, (LPCWSTR)wsServer,
  80. GetLastError()));
  81. return WBEM_E_FAILED;
  82. }
  83. // Get event parameters
  84. // ====================
  85. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_EVENTID, 0, &v, NULL, NULL);
  86. if(SUCCEEDED(hres) && (V_VT(&v) == VT_I4))
  87. m_dwEventId = V_I4(&v);
  88. else
  89. // This will mean we need to try to get the event information off of each
  90. // event class as it arrives.
  91. m_dwEventId = 0;
  92. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_TYPE, 0, &v, NULL, NULL);
  93. if(FAILED(hres) || (V_VT(&v) != VT_I4))
  94. return WBEM_E_INVALID_PARAMETER;
  95. m_dwType = V_I4(&v);
  96. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_CATEGORY, 0, &v, NULL, NULL);
  97. if(FAILED(hres) || (V_VT(&v) != VT_I4))
  98. m_dwCategory = 0;
  99. else
  100. m_dwCategory = V_I4(&v);
  101. if (m_dwCategory > 0xFFFF)
  102. return WBEM_E_INVALID_PARAMETER;
  103. // Get insertion strings
  104. // =====================
  105. // Only get this stuff if the logical consumer has an event id.
  106. if (m_dwEventId)
  107. {
  108. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_NUMSTRINGS, 0, &v,
  109. NULL, NULL);
  110. if(FAILED(hres) || (V_VT(&v) != VT_I4))
  111. return WBEM_E_INVALID_PARAMETER;
  112. m_dwNumTemplates = V_I4(&v);
  113. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_STRINGS, 0, &v, NULL, NULL);
  114. if(FAILED(hres))
  115. return WBEM_E_INVALID_PARAMETER;
  116. // array of bstrs or null, else bail
  117. if ((V_VT(&v) != (VT_BSTR | VT_ARRAY)) && (V_VT(&v) != VT_NULL))
  118. {
  119. VariantClear(&v);
  120. return WBEM_E_INVALID_PARAMETER;
  121. }
  122. if ((V_VT(&v) == VT_NULL) && (m_dwNumTemplates > 0))
  123. return WBEM_E_INVALID_PARAMETER;
  124. if (m_dwNumTemplates > 0)
  125. {
  126. CVarVector vv(VT_BSTR, V_ARRAY(&v));
  127. VariantClear(&v);
  128. if (vv.Size() < m_dwNumTemplates)
  129. return WBEM_E_INVALID_PARAMETER;
  130. m_aTemplates = new CTextTemplate[m_dwNumTemplates];
  131. if(m_aTemplates == NULL)
  132. return WBEM_E_OUT_OF_MEMORY;
  133. for(DWORD i = 0; i < m_dwNumTemplates; i++)
  134. {
  135. m_aTemplates[i].SetTemplate(vv.GetAt(i).GetLPWSTR());
  136. }
  137. }
  138. }
  139. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_DATANAME, 0, &v,
  140. NULL, NULL);
  141. if (SUCCEEDED(hres) && (v.vt == VT_BSTR) && (v.bstrVal != NULL))
  142. {
  143. m_dataName = v.bstrVal;
  144. }
  145. VariantClear(&v);
  146. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_SIDNAME, 0, &v,
  147. NULL, NULL);
  148. if (SUCCEEDED(hres) && (v.vt == VT_BSTR) && (v.bstrVal != NULL))
  149. {
  150. m_sidName = v.bstrVal;
  151. }
  152. VariantClear(&v);
  153. hres = pLogicalConsumer->Get(EVENTLOG_PROPNAME_CREATORSID, 0, &v,
  154. NULL, NULL);
  155. if (SUCCEEDED(hres) && (v.vt != VT_NULL))
  156. {
  157. if((v.vt != (VT_ARRAY | VT_UI1)))
  158. {
  159. VariantClear(&v);
  160. return WBEM_E_INVALID_OBJECT;
  161. }
  162. long ubound;
  163. if(SUCCEEDED(hres = SafeArrayGetUBound(V_ARRAY(&v), 1, &ubound)))
  164. {
  165. PVOID pVoid;
  166. if(SUCCEEDED(hres = SafeArrayAccessData(V_ARRAY(&v), &pVoid)))
  167. {
  168. m_pSidCreator = new BYTE[ubound +1];
  169. if(m_pSidCreator == NULL)
  170. hres = WBEM_E_OUT_OF_MEMORY;
  171. else
  172. memcpy(m_pSidCreator, pVoid, ubound + 1);
  173. SafeArrayUnaccessData(V_ARRAY(&v));
  174. }
  175. }
  176. }
  177. VariantClear(&v);
  178. return hres;
  179. }
  180. HRESULT CEventLogSink::XSink::GetDatEmbeddedObjectOut(IWbemClassObject* pObject, WCHAR* objectName, IWbemClassObject*& pEmbeddedObject)
  181. {
  182. HRESULT hr;
  183. VARIANT vObject;
  184. VariantInit(&vObject);
  185. hr = pObject->Get(objectName, 0, &vObject, NULL, NULL);
  186. if (FAILED(hr))
  187. {
  188. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: could not retrieve %S, 0x%08X\n", objectName, hr));
  189. }
  190. else if ((vObject.vt != VT_UNKNOWN) || (vObject.punkVal == NULL)
  191. || FAILED(vObject.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pEmbeddedObject)))
  192. {
  193. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S is not an embedded object\n", objectName));
  194. hr = WBEM_E_INVALID_PARAMETER;
  195. }
  196. VariantClear(&vObject);
  197. return hr;
  198. }
  199. HRESULT CEventLogSink::XSink::GetDatDataVariant(IWbemClassObject* pEventObj, WCHAR* dataName, VARIANT& vData)
  200. {
  201. WCHAR* propName = NULL;
  202. IWbemClassObject* pDataObj = NULL;
  203. HRESULT hr = WBEM_S_NO_ERROR;
  204. // parse out data name
  205. WCHAR* pDot;
  206. if (pDot = wcschr(dataName, L'.'))
  207. {
  208. // found a dot, we're dealing with an embedded object
  209. // mask out dot to make our life easier
  210. *pDot = L'\0';
  211. WCHAR* pNextDot;
  212. pNextDot = wcschr(pDot+1, L'.');
  213. if (pNextDot)
  214. // we have a doubly embedded object, that's as deep as we support
  215. {
  216. // we now have three prop names with nulls between
  217. *pNextDot = '\0';
  218. IWbemClassObject* pIntermediateObj = NULL;
  219. if (SUCCEEDED(hr = GetDatEmbeddedObjectOut(pEventObj, dataName, pIntermediateObj)))
  220. {
  221. hr = GetDatEmbeddedObjectOut(pIntermediateObj, pDot +1, pDataObj);
  222. pIntermediateObj->Release();
  223. }
  224. propName = pNextDot +1;
  225. // put dot back
  226. *pDot = L'.';
  227. // put dot dot back back
  228. *pNextDot = L'.';
  229. }
  230. else
  231. // we have a singly embedded object. cool.
  232. {
  233. hr = GetDatEmbeddedObjectOut(pEventObj, dataName, pDataObj);
  234. // put dot back
  235. *pDot = L'.';
  236. propName = pDot +1;
  237. }
  238. }
  239. else
  240. {
  241. // not an embedded object
  242. pDataObj = pEventObj;
  243. pDataObj->AddRef();
  244. propName = dataName;
  245. }
  246. if (SUCCEEDED(hr) && pDataObj)
  247. {
  248. if (FAILED(hr = pDataObj->Get(propName, 0, &vData, NULL, NULL)))
  249. DEBUGTRACE((LOG_ESS, "NT Event Log Consumer: could not retrieve property '%S' 0x%08X\n", dataName, hr));
  250. }
  251. if (pDataObj)
  252. pDataObj->Release();
  253. return hr;
  254. }
  255. // assumes that dataName is a valid string
  256. // retrieves data from event object
  257. // upon return pData points at data contained in variant
  258. // calls responsibility to clear variant (don't delete pData)
  259. // void return, any errors are logged - we don't want to block an event log if we can avoid it
  260. void CEventLogSink::XSink::GetDatData(IWbemClassObject* pEventObj, WCHAR* dataName,
  261. VARIANT& vData, BYTE*& pData, DWORD& dataSize)
  262. {
  263. pData = NULL;
  264. dataSize = 0;
  265. HRESULT hr;
  266. if (SUCCEEDED(GetDatDataVariant(pEventObj, dataName, vData)))
  267. {
  268. hr = VariantChangeType(&vData, &vData, 0, (VT_UI1 | VT_ARRAY));
  269. if (FAILED(hr) || (vData.vt != (VT_UI1 | VT_ARRAY)))
  270. {
  271. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S cannot be converted to a byte array (0x%08X)\n", dataName, hr));
  272. VariantClear(&vData);
  273. }
  274. else
  275. // should be good to go!
  276. {
  277. if (FAILED(hr = SafeArrayAccessData(vData.parray, (void**)&pData)))
  278. {
  279. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: failed to access %S, 0x%08X\n", dataName, hr));
  280. VariantClear(&vData);
  281. }
  282. long lDataSize;
  283. SafeArrayGetUBound(vData.parray, 1, &lDataSize);
  284. dataSize = (DWORD)lDataSize + 1;
  285. }
  286. }
  287. }
  288. // assumes that dataName is a valid string
  289. // retrieves data from event object
  290. // void return, any errors are logged - we don't want to block an event log if we can avoid it
  291. void CEventLogSink::XSink::GetDatSID(IWbemClassObject* pEventObj, WCHAR* dataName, PSID& pSid)
  292. {
  293. HRESULT hr;
  294. VARIANT vData;
  295. VariantInit(&vData);
  296. pSid = NULL;
  297. if (SUCCEEDED(hr = GetDatDataVariant(pEventObj, dataName, vData)))
  298. {
  299. if (vData.vt == (VT_UI1 | VT_ARRAY))
  300. {
  301. BYTE* pData;
  302. // this should be a binary SID
  303. if (FAILED(hr = SafeArrayAccessData(vData.parray, (void**)&pData)))
  304. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: failed to access %S, 0x%08X\n", dataName, hr));
  305. else
  306. {
  307. if (IsValidSid((PSID)pData))
  308. {
  309. DWORD l = GetLengthSid((PSID)pData);
  310. if (pSid = new BYTE[l])
  311. CopySid(l, pSid, (PSID)pData);
  312. }
  313. }
  314. }
  315. else if ((vData.vt == VT_BSTR) && (vData.bstrVal != NULL))
  316. {
  317. PSID pLocalSid;
  318. if (!ConvertStringSidToSid(vData.bstrVal, &pLocalSid))
  319. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: cannot convert %S to a SID\n", vData.bstrVal));
  320. else
  321. {
  322. DWORD l = GetLengthSid(pLocalSid);
  323. if (pSid = new BYTE[l])
  324. CopySid(l, pSid, pLocalSid);
  325. FreeSid(pLocalSid);
  326. }
  327. }
  328. else
  329. ERRORTRACE((LOG_ESS, "NT Event Log Consumer: %S is not a SID\n", dataName));
  330. VariantClear(&vData);
  331. }
  332. }
  333. HRESULT STDMETHODCALLTYPE CEventLogSink::XSink::IndicateToConsumer(
  334. IWbemClassObject* pLogicalConsumer, long lNumObjects,
  335. IWbemClassObject** apObjects)
  336. {
  337. HRESULT hr = WBEM_S_NO_ERROR;
  338. if (IsNT())
  339. {
  340. PSID pSidSystem;
  341. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  342. if (AllocateAndInitializeSid(&id, 1,
  343. SECURITY_LOCAL_SYSTEM_RID,
  344. 0, 0,0,0,0,0,0,&pSidSystem))
  345. {
  346. // guilty until proven innocent
  347. hr = WBEM_E_ACCESS_DENIED;
  348. // check to see if sid is either Local System or an admin of some sort...
  349. if ((EqualSid(pSidSystem, m_pObject->m_pSidCreator)) ||
  350. (S_OK == IsUserAdministrator(m_pObject->m_pSidCreator)))
  351. hr = WBEM_S_NO_ERROR;
  352. // We're done with this
  353. FreeSid(pSidSystem);
  354. if (FAILED(hr))
  355. return hr;
  356. }
  357. else
  358. return WBEM_E_OUT_OF_MEMORY;
  359. }
  360. for(int i = 0; i < lNumObjects; i++)
  361. {
  362. int j;
  363. BOOL bRes = FALSE;
  364. // Do all events use the same ID?
  365. if (m_pObject->m_dwEventId)
  366. {
  367. BSTR* astrStrings = new BSTR[m_pObject->m_dwNumTemplates];
  368. if(astrStrings == NULL)
  369. return WBEM_E_OUT_OF_MEMORY;
  370. for(j = 0; j < m_pObject->m_dwNumTemplates; j++)
  371. {
  372. BSTR strText = m_pObject->m_aTemplates[j].Apply(apObjects[i]);
  373. if(strText == NULL)
  374. {
  375. strText = SysAllocString(L"invalid log entry");
  376. if(strText == NULL)
  377. {
  378. delete [] astrStrings;
  379. return WBEM_E_OUT_OF_MEMORY;
  380. }
  381. }
  382. astrStrings[j] = strText;
  383. }
  384. DWORD dataSize = NULL;
  385. // data is actually held in the variant
  386. // pData just makes access easier (clear the variant, don't delete pData!)
  387. VARIANT vData;
  388. VariantInit(&vData);
  389. BYTE *pData = NULL;
  390. PSID pSid = NULL;
  391. if (m_pObject->m_dataName.Length() > 0)
  392. GetDatData(apObjects[i], m_pObject->m_dataName, vData, pData, dataSize);
  393. if (m_pObject->m_sidName.Length() > 0)
  394. GetDatSID(apObjects[i], m_pObject->m_sidName, pSid);
  395. bRes = ReportEventW(m_pObject->m_hEventLog, m_pObject->m_dwType,
  396. m_pObject->m_dwCategory, m_pObject->m_dwEventId, pSid,
  397. m_pObject->m_dwNumTemplates, dataSize,
  398. (LPCWSTR*)astrStrings, pData);
  399. // sid was allocated as an array of BYTE, not via AllocateAndInitializeSid
  400. if (pSid)
  401. delete[] pSid;
  402. if (vData.vt == (VT_UI1 | VT_ARRAY))
  403. SafeArrayUnaccessData(vData.parray);
  404. VariantClear(&vData);
  405. pData = NULL;
  406. if(!bRes)
  407. {
  408. ERRORTRACE((LOG_ESS, "Failed to log an event: %X\n",
  409. GetLastError()));
  410. hr = WBEM_E_FAILED;
  411. }
  412. for(j = 0; j < m_pObject->m_dwNumTemplates; j++)
  413. {
  414. SysFreeString(astrStrings[j]);
  415. }
  416. delete [] astrStrings;
  417. }
  418. // If each event supplies its own ID, we have some work to do.
  419. else
  420. {
  421. IWbemQualifierSet *pQuals = NULL;
  422. if (SUCCEEDED(apObjects[i]->GetQualifierSet(&pQuals)))
  423. {
  424. _variant_t vMsgID;
  425. if (SUCCEEDED(pQuals->Get(EVENTLOG_PROPNAME_EVENTID, 0, &vMsgID, NULL)) &&
  426. ((vMsgID.vt == VT_BSTR) || (vMsgID.vt == VT_I4)))
  427. {
  428. _variant_t vTemplates;
  429. BSTR *pstrInsertionStrings = NULL;
  430. DWORD nStrings = 0;
  431. if (SUCCEEDED(pQuals->Get(
  432. EVENTLOG_PROPNAME_STRINGS, 0, &vTemplates, NULL)) &&
  433. vTemplates.vt == (VT_ARRAY | VT_BSTR) &&
  434. vTemplates.parray->rgsabound[0].cElements > 0)
  435. {
  436. CTextTemplate *pTemplates;
  437. nStrings = vTemplates.parray->rgsabound[0].cElements;
  438. pTemplates = new CTextTemplate[nStrings];
  439. if(pTemplates == NULL)
  440. return WBEM_E_OUT_OF_MEMORY;
  441. pstrInsertionStrings = new BSTR[nStrings];
  442. if(pstrInsertionStrings == NULL)
  443. {
  444. delete [] pTemplates;
  445. return WBEM_E_OUT_OF_MEMORY;
  446. }
  447. if (pTemplates && pstrInsertionStrings)
  448. {
  449. BSTR *pTemplateStrings = (BSTR*) vTemplates.parray->pvData;
  450. for (j = 0; j < nStrings; j++)
  451. {
  452. pTemplates[j].SetTemplate(pTemplateStrings[j]);
  453. pstrInsertionStrings[j] = pTemplates[j].Apply(apObjects[i]);
  454. }
  455. }
  456. else
  457. nStrings = 0;
  458. if (pTemplates)
  459. delete [] pTemplates;
  460. }
  461. DWORD dwEventID,
  462. dwType,
  463. dwCategory;
  464. _variant_t vTemp;
  465. WCHAR *szBad;
  466. if (vMsgID.vt == VT_BSTR)
  467. dwEventID = wcstoul(V_BSTR(&vMsgID), &szBad, 10);
  468. else if (vMsgID.vt == VT_I4)
  469. dwEventID = V_I4(&vMsgID);
  470. if ((SUCCEEDED(pQuals->Get(EVENTLOG_PROPNAME_TYPE, 0, &vTemp, NULL))) &&
  471. (V_VT(&vTemp) == VT_I4))
  472. dwType = V_I4(&vTemp);
  473. else
  474. dwType = m_pObject->m_dwType;
  475. if (SUCCEEDED(pQuals->Get(
  476. EVENTLOG_PROPNAME_CATEGORY, 0, &vTemp, NULL)))
  477. dwCategory = V_I4(&vTemp);
  478. else
  479. dwCategory = m_pObject->m_dwCategory;
  480. DWORD dataSize = NULL;
  481. // data is actually held in the variant
  482. // pData just makes access easier (clear the variant, don't delete pData!)
  483. VARIANT vData;
  484. VariantInit(&vData);
  485. BYTE *pData = NULL;
  486. PSID pSid = NULL;
  487. if (m_pObject->m_dataName.Length() > 0)
  488. GetDatData(apObjects[i], m_pObject->m_dataName, vData, pData, dataSize);
  489. if (m_pObject->m_sidName.Length() > 0)
  490. GetDatSID(apObjects[i], m_pObject->m_sidName, pSid);
  491. bRes =
  492. ReportEventW(
  493. m_pObject->m_hEventLog,
  494. dwType,
  495. dwCategory,
  496. dwEventID,
  497. pSid,
  498. nStrings,
  499. dataSize,
  500. (LPCWSTR*) pstrInsertionStrings,
  501. pData);
  502. // sid was allocated as an array of BYTE, not via AllocateAndInitializeSid
  503. if (pSid)
  504. delete[] pSid;
  505. if (vData.vt == (VT_UI1 | VT_ARRAY))
  506. SafeArrayUnaccessData(vData.parray);
  507. VariantClear(&vData);
  508. pData = NULL;
  509. if (!bRes)
  510. {
  511. ERRORTRACE((LOG_ESS, "Failed to log an event: %X\n",
  512. GetLastError()));
  513. hr = WBEM_E_FAILED;
  514. }
  515. for (j = 0; j < nStrings; j++)
  516. SysFreeString(pstrInsertionStrings[j]);
  517. delete [] pstrInsertionStrings;
  518. } // SUCCEEDED(Get)
  519. pQuals->Release();
  520. } // SUCCEEDED(GetQualifierSet)
  521. }
  522. }
  523. return hr;
  524. }
  525. void* CEventLogSink::GetInterface(REFIID riid)
  526. {
  527. if(riid == IID_IWbemUnboundObjectSink)
  528. return &m_XSink;
  529. else return NULL;
  530. }