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.

1991 lines
49 KiB

  1. //***************************************************************************
  2. //
  3. // NTEVTLOGR.CPP
  4. //
  5. // Module: WBEM NT EVENT PROVIDER
  6. //
  7. // Purpose: Contains the Eventlog record classes
  8. //
  9. // Copyright (c) 1996-2002 Microsoft Corporation, All Rights Reserved
  10. //
  11. //***************************************************************************
  12. #include "precomp.h"
  13. #include <time.h>
  14. #include <wbemtime.h>
  15. #include <Ntdsapi.h>
  16. #include <Sddl.h>
  17. #include <autoptr.h>
  18. #include <scopeguard.h>
  19. #define MAX_INSERT_OPS 100
  20. CEventlogRecord::CEventlogRecord(const wchar_t* logfile, const EVENTLOGRECORD* pEvt, IWbemServices* ns,
  21. IWbemClassObject* pClass, IWbemClassObject* pAClass)
  22. : m_nspace(NULL), m_pClass(NULL), m_pAClass(NULL)
  23. {
  24. m_EvtType = 0;
  25. m_Data = NULL;
  26. m_Obj = NULL;
  27. m_NumStrs = 0;
  28. m_DataLen = 0;
  29. m_nspace = ns;
  30. if (m_nspace != NULL)
  31. {
  32. m_nspace->AddRef();
  33. }
  34. else
  35. {
  36. m_pClass = pClass;
  37. if (m_pClass != NULL)
  38. {
  39. m_pClass->AddRef();
  40. }
  41. m_pAClass = pAClass;
  42. if (m_pAClass != NULL)
  43. {
  44. m_pAClass->AddRef();
  45. }
  46. }
  47. if ((NULL == logfile) || ((m_pClass == NULL) && (m_nspace == NULL)))
  48. {
  49. m_Valid = FALSE;
  50. DebugOut(
  51. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  52. _T(__FILE__),__LINE__,
  53. L"CEventlogRecord::CEventlogRecord:Created INVALID Record\r\n"
  54. ) ;
  55. )
  56. }
  57. else
  58. {
  59. m_Logfile = logfile;
  60. m_Valid = Init(pEvt);
  61. }
  62. }
  63. CEventlogRecord::~CEventlogRecord()
  64. {
  65. if (m_pClass != NULL)
  66. {
  67. m_pClass->Release();
  68. }
  69. if (m_pAClass != NULL)
  70. {
  71. m_pAClass->Release();
  72. }
  73. if (m_nspace != NULL)
  74. {
  75. m_nspace->Release();
  76. }
  77. for (LONG x = 0; x < m_NumStrs; x++)
  78. {
  79. delete [] m_InsStrs[x];
  80. }
  81. if (m_Data != NULL)
  82. {
  83. delete [] m_Data;
  84. }
  85. if (m_Obj != NULL)
  86. {
  87. m_Obj->Release();
  88. }
  89. }
  90. BOOL CEventlogRecord::Init(const EVENTLOGRECORD* pEvt)
  91. {
  92. if (NULL == pEvt)
  93. {
  94. DebugOut(
  95. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  96. _T(__FILE__),__LINE__,
  97. L"CEventlogRecord::Init:No DATA return FALSE\r\n"
  98. ) ;
  99. )
  100. return FALSE;
  101. }
  102. if (!GetInstance())
  103. {
  104. return FALSE;
  105. }
  106. m_Record = pEvt->RecordNumber;
  107. m_EvtID = pEvt->EventID;
  108. m_SourceName = (const wchar_t*)((UCHAR*)pEvt + sizeof(EVENTLOGRECORD));
  109. m_CompName = (const wchar_t*)((UCHAR*)pEvt + sizeof(EVENTLOGRECORD)) + wcslen(m_SourceName) + 1;
  110. SetType(pEvt->EventType);
  111. m_Category = pEvt->EventCategory;
  112. SetTimeStr(m_TimeGen, pEvt->TimeGenerated);
  113. SetTimeStr(m_TimeWritten, pEvt->TimeWritten);
  114. if (pEvt->UserSidLength > 0)
  115. {
  116. PSID pSid = NULL;
  117. pSid = (PSID)((UCHAR*)pEvt + pEvt->UserSidOffset);
  118. if ( pSid && IsValidSid ( pSid ) )
  119. {
  120. SetUser( pSid );
  121. }
  122. }
  123. if (pEvt->NumStrings)
  124. {
  125. //Must have an element for every expected insertion string
  126. //don't know how many that is so create max size array and
  127. //intitialize all to NULL
  128. memset(m_InsStrs, 0, MAX_NUM_OF_INS_STRS * sizeof(wchar_t*));
  129. const wchar_t* pstr = (const wchar_t*)((UCHAR*)pEvt + pEvt->StringOffset);
  130. for (WORD x = 0; x < pEvt->NumStrings; x++)
  131. {
  132. LONG len = wcslen(pstr) + 1;
  133. m_InsStrs[x] = new wchar_t[len];
  134. m_NumStrs++;
  135. StringCchCopyW ( m_InsStrs[x], len, pstr );
  136. pstr += len;
  137. }
  138. }
  139. SetMessage();
  140. if (pEvt->DataLength)
  141. {
  142. m_Data = new UCHAR[pEvt->DataLength];
  143. m_DataLen = pEvt->DataLength;
  144. memcpy((void*)m_Data, (void*)((UCHAR*)pEvt + pEvt->DataOffset), pEvt->DataLength);
  145. }
  146. return TRUE;
  147. }
  148. BOOL CEventlogRecord::GenerateInstance(IWbemClassObject** ppInst)
  149. {
  150. if (ppInst == NULL)
  151. {
  152. DebugOut(
  153. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  154. _T(__FILE__),__LINE__,
  155. L"CEventlogRecord::GenerateInstance:Invalid parameter\r\n"
  156. ) ;
  157. )
  158. return FALSE;
  159. }
  160. *ppInst = NULL;
  161. if (!m_Valid)
  162. {
  163. DebugOut(
  164. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  165. _T(__FILE__),__LINE__,
  166. L"CEventlogRecord::GenerateInstance:Invalid record\r\n"
  167. ) ;
  168. )
  169. return FALSE;
  170. }
  171. if (!SetProperty(LOGFILE_PROP, m_Logfile))
  172. {
  173. m_Valid = FALSE;
  174. DebugOut(
  175. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  176. _T(__FILE__),__LINE__,
  177. L"CEventlogRecord::GenerateInstance:Failed to set key\r\n"
  178. ) ;
  179. )
  180. return FALSE;
  181. }
  182. else
  183. {
  184. DebugOut(
  185. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  186. _T(__FILE__),__LINE__,
  187. L"CEventlogRecord::GenerateInstance:Log: %s\r\n", m_Logfile
  188. ) ;
  189. )
  190. }
  191. if (!SetProperty(RECORD_PROP, m_Record))
  192. {
  193. m_Valid = FALSE;
  194. DebugOut(
  195. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  196. _T(__FILE__),__LINE__,
  197. L"CEventlogRecord::GenerateInstance:Failed to set key\r\n"
  198. ) ;
  199. )
  200. return FALSE;
  201. }
  202. else
  203. {
  204. DebugOut(
  205. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  206. _T(__FILE__),__LINE__,
  207. L"CEventlogRecord::GenerateInstance:Record: %d\r\n", m_Record
  208. ) ;
  209. )
  210. }
  211. SetProperty(TYPE_PROP, m_Type);
  212. SetProperty(EVTTYPE_PROP, (DWORD)m_EvtType);
  213. if (!m_SourceName.IsEmpty())
  214. {
  215. SetProperty(SOURCE_PROP, m_SourceName);
  216. DebugOut(
  217. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  218. _T(__FILE__),__LINE__,
  219. L"CEventlogRecord::GenerateInstance:Source: %s\r\n", m_SourceName
  220. ) ;
  221. )
  222. }
  223. SetProperty(EVTID_PROP, m_EvtID);
  224. SetProperty(EVTID2_PROP, (m_EvtID & 0xFFFF));
  225. if (!m_TimeGen.IsEmpty())
  226. {
  227. DebugOut(
  228. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  229. _T(__FILE__),__LINE__,
  230. L"CEventlogRecord::GenerateInstance:TimeGenerated: %s\r\n", m_TimeGen
  231. ) ;
  232. )
  233. SetProperty(GENERATED_PROP, m_TimeGen);
  234. }
  235. if (!m_TimeWritten.IsEmpty())
  236. {
  237. SetProperty(WRITTEN_PROP, m_TimeWritten);
  238. }
  239. if (!m_CompName.IsEmpty())
  240. {
  241. SetProperty(COMPUTER_PROP, m_CompName);
  242. }
  243. if (!m_User.IsEmpty())
  244. {
  245. SetProperty(USER_PROP, m_User);
  246. }
  247. if (!m_Message.IsEmpty())
  248. {
  249. SetProperty(MESSAGE_PROP, m_Message);
  250. }
  251. if (!m_CategoryString.IsEmpty())
  252. {
  253. SetProperty(CATSTR_PROP, m_CategoryString);
  254. }
  255. SetProperty(CATEGORY_PROP, (DWORD)m_Category);
  256. VARIANT v;
  257. if (m_Data != NULL)
  258. {
  259. SAFEARRAYBOUND rgsabound[1];
  260. SAFEARRAY* psa = NULL;
  261. UCHAR* pdata = NULL;
  262. rgsabound[0].lLbound = 0;
  263. VariantInit(&v);
  264. rgsabound[0].cElements = m_DataLen;
  265. psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
  266. if (NULL != psa)
  267. {
  268. v.vt = VT_ARRAY|VT_UI1;
  269. v.parray = psa;
  270. if (SUCCEEDED(SafeArrayAccessData(psa, (void **)&pdata)))
  271. {
  272. memcpy((void *)pdata, (void *)m_Data, m_DataLen);
  273. SafeArrayUnaccessData(psa);
  274. m_Obj->Put(DATA_PROP, 0, &v, 0);
  275. }
  276. else
  277. {
  278. VariantClear (&v) ;
  279. return FALSE ;
  280. }
  281. }
  282. else
  283. {
  284. VariantClear(&v);
  285. return FALSE ;
  286. }
  287. VariantClear(&v);
  288. }
  289. if (0 != m_NumStrs)
  290. {
  291. SAFEARRAYBOUND rgsabound[1];
  292. SAFEARRAY* psa = NULL;
  293. BSTR* pBstr = NULL;
  294. rgsabound[0].lLbound = 0;
  295. VariantInit(&v);
  296. rgsabound[0].cElements = m_NumStrs;
  297. psa = SafeArrayCreate(VT_BSTR, 1, rgsabound);
  298. if (NULL != psa)
  299. {
  300. v.vt = VT_ARRAY|VT_BSTR;
  301. v.parray = psa;
  302. if (SUCCEEDED(SafeArrayAccessData(psa, (void **)&pBstr)))
  303. {
  304. for (LONG x = 0; x < m_NumStrs; x++)
  305. {
  306. pBstr[x] = SysAllocString(m_InsStrs[x]);
  307. if ( NULL == pBstr[x] )
  308. {
  309. SafeArrayUnaccessData(psa);
  310. VariantClear (&v) ;
  311. return FALSE ;
  312. }
  313. }
  314. SafeArrayUnaccessData(psa);
  315. m_Obj->Put(INSSTRS_PROP, 0, &v, 0);
  316. }
  317. else
  318. {
  319. VariantClear (&v) ;
  320. return FALSE ;
  321. }
  322. }
  323. else
  324. {
  325. VariantClear(&v);
  326. return FALSE ;
  327. }
  328. VariantClear(&v);
  329. }
  330. *ppInst = m_Obj;
  331. m_Obj->AddRef();
  332. return TRUE;
  333. }
  334. BOOL CEventlogRecord::SetProperty(wchar_t* prop, CStringW val)
  335. {
  336. VARIANT v;
  337. VariantInit(&v);
  338. v.vt = VT_BSTR;
  339. v.bstrVal = val.AllocSysString();
  340. HRESULT hr = m_Obj->Put(prop, 0, &v, 0);
  341. VariantClear(&v);
  342. if (FAILED(hr))
  343. {
  344. DebugOut(
  345. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  346. _T(__FILE__),__LINE__,
  347. L"CEventlogRecord::SetProperty:Failed to set %s with %s\r\n",
  348. prop, val
  349. ) ;
  350. )
  351. return FALSE;
  352. }
  353. return TRUE;
  354. }
  355. BOOL CEventlogRecord::SetProperty(wchar_t* prop, DWORD val)
  356. {
  357. VARIANT v;
  358. VariantInit(&v);
  359. v.vt = VT_I4;
  360. v.lVal = val;
  361. HRESULT hr = m_Obj->Put(prop, 0, &v, 0);
  362. VariantClear(&v);
  363. if (FAILED(hr))
  364. {
  365. DebugOut(
  366. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  367. _T(__FILE__),__LINE__,
  368. L"CEventlogRecord::SetProperty:Failed to set %s with %lx\r\n",
  369. prop, val
  370. ) ;
  371. )
  372. return FALSE;
  373. }
  374. return TRUE;
  375. }
  376. void CEventlogRecord::SetUser(PSID psidUserSid)
  377. {
  378. m_User = GetUser(psidUserSid);
  379. }
  380. ULONG CEventlogRecord::CheckInsertionStrings(HKEY hk, HKEY hkPrimary)
  381. {
  382. //
  383. // If the message doesn't have any percent signs, it can't have any
  384. // insertions.
  385. //
  386. if (!m_Message.IsEmpty() && !wcschr(m_Message, L'%'))
  387. {
  388. return 0;
  389. }
  390. HINSTANCE hParamModule = NULL;
  391. CStringW paramModule = CEventLogFile::GetFileName(hk, PARAM_MODULE);
  392. if (paramModule.IsEmpty())
  393. {
  394. if ( hkPrimary )
  395. {
  396. paramModule = CEventLogFile::GetFileName(hkPrimary, PARAM_MODULE);
  397. }
  398. }
  399. if (!paramModule.IsEmpty())
  400. {
  401. hParamModule = GetDll(paramModule);
  402. }
  403. ULONG size = 0;
  404. LPWSTR Message = NULL;
  405. Message = new WCHAR [ ( m_Message.GetLength() + 1 ) ];
  406. StringCchCopy ( Message, m_Message.GetLength() + 1, m_Message );
  407. wchar_t* lpszString = Message; // set initial pointer
  408. UINT nInsertions = 0; // limit number of recursions
  409. while ( lpszString && *lpszString )
  410. {
  411. wchar_t* lpStartDigit = wcschr(lpszString, L'%');
  412. //
  413. // If there are no more insertion markers in the source string,
  414. // we're done.
  415. //
  416. if (lpStartDigit == NULL)
  417. {
  418. break;
  419. }
  420. //
  421. // get the offset of %string from the beggining of buffer for future replacement
  422. //
  423. UINT nOffset = (DWORD) ( lpStartDigit - Message );
  424. UINT nStrSize = wcslen ( lpStartDigit );
  425. //
  426. // Found a possible insertion marker. If it's followed by a
  427. // number, it's an insert string. If it's followed by another
  428. // percent, it could be a parameter insert.
  429. //
  430. if ( nStrSize > 1 && lpStartDigit[1] >= L'0' && lpStartDigit[1] <= L'9' )
  431. {
  432. // Object with percent-sign in name messes up object access audit
  433. // This might fail because an inserted string itself contained
  434. // text which looks like an insertion parameter, such as "%20".
  435. // Ignore the return value and continue with further replacements.
  436. (void) ReplaceStringInsert (
  437. &Message,
  438. nOffset,
  439. &lpStartDigit,
  440. &size
  441. );
  442. // set pointer to the beginning of replacement
  443. lpszString = lpStartDigit;
  444. //
  445. // If we've reached the limit of insertion operations, quit.
  446. // This shouldn't normally happen and could indicate that
  447. // the insert strings or parameter strings are self referencing
  448. // and would create an infinite loop.
  449. //
  450. if (++nInsertions >= MAX_INSERT_OPS)
  451. {
  452. break;
  453. }
  454. }
  455. else if ( nStrSize > 2 && lpStartDigit[1] == '%' )
  456. {
  457. //
  458. // Found %%. If that is followed by a digit, it's a parameter string.
  459. //
  460. if (lpStartDigit[2] >= L'0' && lpStartDigit[2] <= L'9')
  461. {
  462. if ( SUCCEEDED ( ReplaceParameterInsert (
  463. hParamModule,
  464. paramModule,
  465. &Message,
  466. nOffset,
  467. &lpStartDigit,
  468. &size
  469. )
  470. )
  471. )
  472. {
  473. // set pointer to the beginning of replacement
  474. lpszString = lpStartDigit;
  475. //
  476. // If we've reached the limit of insertion operations, quit.
  477. // This shouldn't normally happen and could indicate that
  478. // the insert strings or parameter strings are self referencing
  479. // and would create an infinite loop.
  480. //
  481. if (++nInsertions >= MAX_INSERT_OPS)
  482. {
  483. break;
  484. }
  485. }
  486. else
  487. {
  488. //
  489. // unable to replace (error). Just keep moving.
  490. //
  491. lpszString++;
  492. }
  493. }
  494. else if ( nStrSize > 3 && lpStartDigit[2] == '%' )
  495. {
  496. //
  497. // Found %%%. If that is followed by a digit, it's a insertion string.
  498. //
  499. if (lpStartDigit[3] >= L'0' && lpStartDigit[3] <= L'9')
  500. {
  501. //
  502. // Got %%%n, where n is a number. For compatibility with
  503. // old event viewer, must replace this with %%x, where x
  504. // is insertion string n. If insertion string n is itself
  505. // a number m, this becomes %%m, which is treated as parameter
  506. // message number m.
  507. //
  508. lpStartDigit += 2; // point at %n
  509. //
  510. // nOffset shows offset from the beginning of the buffer where
  511. // replacement is going to happen to first % character lpStartDigit
  512. //
  513. // as we are chaging %%%n to be be %%x where x = %n, implementation
  514. // needs to move offset to point to the x here to get correct replacement
  515. //
  516. if ( SUCCEEDED ( ReplaceStringInsert (
  517. &Message,
  518. nOffset+2,
  519. &lpStartDigit,
  520. &size
  521. )
  522. )
  523. )
  524. {
  525. //
  526. // set pointer to the beginning of %%x (x=%n)
  527. //
  528. // this operation is done by substract as lpStartDigit pointer could
  529. // possibly change when original buffer gets reallocated
  530. //
  531. lpszString = lpStartDigit-2;
  532. //
  533. // If we've reached the limit of insertion operations, quit.
  534. // This shouldn't normally happen and could indicate that
  535. // the insert strings or parameter strings are self referencing
  536. // and would create an infinite loop.
  537. //
  538. if (++nInsertions >= MAX_INSERT_OPS)
  539. {
  540. break;
  541. }
  542. }
  543. else
  544. {
  545. //
  546. // unable to replace (error). Just keep moving.
  547. //
  548. lpszString++;
  549. }
  550. }
  551. else
  552. {
  553. //
  554. // Got %%%x, where x is non-digit. skip first percent;
  555. // maybe x is % and is followed by digit.
  556. //
  557. lpszString++;
  558. }
  559. }
  560. else
  561. {
  562. //
  563. // Got %%x, where x is non-digit. skip first percent;
  564. // maybe x is % and is followed by digit.
  565. //
  566. lpszString++;
  567. }
  568. }
  569. else if (nStrSize >= 3 && (lpStartDigit[1] == L'{') && (lpStartDigit[2] != L'S'))
  570. {
  571. // Parameters of form %{guid}, where {guid} is a string of
  572. // hex digits in the form returned by ::StringFromGUID2 (e.g.
  573. // {c200e360-38c5-11ce-ae62-08002b2b79ef}), and represents a
  574. // unique object in the Active Directory.
  575. //
  576. // These parameters are only found in the security event logs
  577. // of NT5 domain controllers. We will attempt to map the guid
  578. // to the human-legible name of the DS object. Failing to find
  579. // a mapping, we will leave the parameter untouched.
  580. // look for closing }
  581. wchar_t *strEnd = wcschr(lpStartDigit + 2, L'}');
  582. if (!strEnd)
  583. {
  584. //ignore this %{?
  585. lpszString++;
  586. }
  587. else
  588. {
  589. //guid string braces but no percent sign...
  590. CStringW strGUID((LPWSTR)(lpStartDigit+1), (int)(strEnd - lpStartDigit));
  591. strEnd++; // now points past '}'
  592. wchar_t t_csbuf[MAX_COMPUTERNAME_LENGTH + 1];
  593. DWORD t_csbuflen = MAX_COMPUTERNAME_LENGTH + 1;
  594. if (GetComputerName(t_csbuf, &t_csbuflen))
  595. {
  596. CStringW temp = GetMappedGUID(t_csbuf, strGUID);
  597. if (temp.GetLength())
  598. {
  599. DWORD nParmSize = strEnd - lpStartDigit;
  600. if ( SUCCEEDED ( ReplaceSubStr (
  601. temp,
  602. &Message,
  603. nOffset,
  604. nParmSize,
  605. &lpStartDigit,
  606. &size
  607. )
  608. )
  609. )
  610. {
  611. // set pointer to the beginning of replacement
  612. lpszString = lpStartDigit;
  613. //
  614. // If we've reached the limit of insertion operations, quit.
  615. // This shouldn't normally happen and could indicate that
  616. // the insert strings or parameter strings are self referencing
  617. // and would create an infinite loop.
  618. //
  619. if (++nInsertions >= MAX_INSERT_OPS)
  620. {
  621. break;
  622. }
  623. }
  624. else
  625. {
  626. //
  627. // unable to replace (error). Just keep moving.
  628. //
  629. lpszString = strEnd;
  630. }
  631. }
  632. else
  633. {
  634. // couldn't get a replacement, so skip it.
  635. lpszString = strEnd;
  636. }
  637. }
  638. else
  639. {
  640. // couldn't get a replacement, so skip it.
  641. lpszString = strEnd;
  642. }
  643. }
  644. }
  645. else if (nStrSize >= 3 && (lpStartDigit[1] == L'{') && (lpStartDigit[2] == L'S'))
  646. {
  647. //
  648. // Parameters of form %{S}, where S is a string-ized SID returned
  649. // by ConvertSidToStringSid, are converted to an object name if
  650. // possible.
  651. //
  652. // look for closing }
  653. wchar_t *strEnd = wcschr(lpStartDigit + 2, L'}');
  654. if (!strEnd)
  655. {
  656. //ignore this %{?
  657. lpszString++;
  658. }
  659. else
  660. {
  661. //sid string no braces or percent sign...
  662. CStringW strSID((LPWSTR)(lpStartDigit+2), (int)(strEnd - lpStartDigit - 2));
  663. strEnd++; // now points past '}'
  664. PSID t_pSid = NULL;
  665. if (ConvertStringSidToSid((LPCWSTR) strSID, &t_pSid))
  666. {
  667. CStringW temp = GetUser(t_pSid);
  668. LocalFree(t_pSid);
  669. if (temp.GetLength())
  670. {
  671. DWORD nParmSize = strEnd - lpStartDigit;
  672. if ( SUCCEEDED ( ReplaceSubStr (
  673. temp,
  674. &Message,
  675. nOffset,
  676. nParmSize,
  677. &lpStartDigit,
  678. &size
  679. )
  680. )
  681. )
  682. {
  683. // set pointer to the beginning of replacement
  684. lpszString = lpStartDigit;
  685. //
  686. // If we've reached the limit of insertion operations, quit.
  687. // This shouldn't normally happen and could indicate that
  688. // the insert strings or parameter strings are self referencing
  689. // and would create an infinite loop.
  690. //
  691. if (++nInsertions >= MAX_INSERT_OPS)
  692. {
  693. break;
  694. }
  695. }
  696. else
  697. {
  698. //
  699. // unable to replace (error). Just keep moving.
  700. //
  701. lpszString = strEnd;
  702. }
  703. }
  704. else
  705. {
  706. // couldn't get a replacement, so skip it.
  707. lpszString = strEnd;
  708. }
  709. }
  710. else
  711. {
  712. // couldn't get a replacement, so skip it.
  713. lpszString = strEnd;
  714. }
  715. }
  716. }
  717. else
  718. {
  719. //
  720. // Found %x where x is neither a % nor a digit. Just keep moving.
  721. //
  722. lpszString++;
  723. }
  724. }
  725. m_Message.Empty();
  726. m_Message = Message;
  727. delete [] Message;
  728. Message = NULL;
  729. return size;
  730. }
  731. //+--------------------------------------------------------------------------
  732. //
  733. // Function: ReplaceStringInsert
  734. //
  735. // Synopsis: Replace the string insert (%n, where n is a number) at
  736. // [Message + nOffset] with insert string number n from the
  737. // event log record [lpParmBuffer].
  738. //
  739. // Modifies: lpStartDigit to point to replacement
  740. //
  741. //---------------------------------------------------------------------------
  742. HRESULT CEventlogRecord::ReplaceStringInsert (
  743. LPWSTR* ppwszBuf,
  744. ULONG nOffset,
  745. LPWSTR* ppwszReplacement,
  746. ULONG* pulSize
  747. )
  748. {
  749. HRESULT hr = E_INVALIDARG;
  750. *ppwszReplacement += 1; // point to start of potential digit
  751. if (**ppwszReplacement != 0) // check to see there is
  752. {
  753. LPWSTR pwszEnd = NULL;
  754. ULONG idxInsertStr = wcstoul(*ppwszReplacement, &pwszEnd, 10);
  755. if ( idxInsertStr && idxInsertStr <= m_NumStrs )
  756. {
  757. DWORD nParmSize = pwszEnd - *ppwszReplacement + 1;
  758. hr = ReplaceSubStr (
  759. m_InsStrs [ idxInsertStr-1 ],
  760. ppwszBuf,
  761. nOffset,
  762. nParmSize,
  763. ppwszReplacement,
  764. pulSize
  765. );
  766. }
  767. //
  768. // else
  769. // {
  770. // we fail as we didn't recognize replacement
  771. // and/or insertion string
  772. //
  773. // see comment in CheckInsertionString
  774. // }
  775. }
  776. return hr;
  777. }
  778. //+--------------------------------------------------------------------------
  779. //
  780. // Function: ReplaceParameterInsert
  781. //
  782. // Synopsis: Replace the parameter insert (double percent sign number) at
  783. // [ppwszReplacement] with a string loaded from a parameter message
  784. // file module.
  785. //
  786. //---------------------------------------------------------------------------
  787. HRESULT CEventlogRecord::ReplaceParameterInsert (
  788. HINSTANCE& hParamModule,
  789. CStringW& paramModule,
  790. LPWSTR* ppwszBuf,
  791. ULONG nOffset,
  792. LPWSTR* ppwszReplacement,
  793. ULONG* pulSize
  794. )
  795. {
  796. DWORD nChars = 0;
  797. wchar_t* lpParmBuffer = NULL;
  798. ULONG nParmSize = 0;
  799. ULONG flFmtMsgFlags =
  800. FORMAT_MESSAGE_IGNORE_INSERTS |
  801. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  802. FORMAT_MESSAGE_MAX_WIDTH_MASK;
  803. LPWSTR pwszEnd = NULL;
  804. ULONG idxParameterStr = wcstoul(*ppwszReplacement + 2, &pwszEnd, 10);
  805. HRESULT hr = E_FAIL;
  806. // Allow "%%0"
  807. if ( idxParameterStr || (L'0' == *(*ppwszReplacement + 2)))
  808. {
  809. if (hParamModule != NULL)
  810. {
  811. nChars = FormatMessage (
  812. flFmtMsgFlags |
  813. FORMAT_MESSAGE_FROM_HMODULE, // look thru message DLL
  814. (LPVOID) hParamModule, // use parameter file
  815. idxParameterStr, // parameter number to get
  816. (ULONG) NULL, // specify no language
  817. (LPWSTR) &lpParmBuffer, // address for buffer pointer
  818. 256, // minimum space to allocate
  819. NULL // no inserted strings
  820. );
  821. }
  822. if (nChars == 0)
  823. {
  824. if (hParamModule != NULL)
  825. {
  826. LocalFree(lpParmBuffer);
  827. lpParmBuffer = NULL;
  828. }
  829. //
  830. // It is common practice to write events with an insertion string whose
  831. // value is %%n, where n is a win32 error code, and to specify a
  832. // parameter message file of kernel32.dll. Unfortunately, kernel32.dll
  833. // doesn't contain messages for all win32 error codes.
  834. //
  835. // So if the parameter wasn't found, and the parameter message file was
  836. // kernel32.dll, attempt a format message from system.
  837. //
  838. paramModule.MakeLower();
  839. if ( wcsstr( paramModule, L"kernel32.dll") )
  840. {
  841. nChars = FormatMessage (
  842. flFmtMsgFlags |
  843. FORMAT_MESSAGE_FROM_SYSTEM, // look thru system
  844. NULL, // no module
  845. idxParameterStr, // parameter number to get
  846. (ULONG) NULL, // specify no language
  847. (LPWSTR) &lpParmBuffer, // address for buffer pointer
  848. 256, // minimum space to allocate
  849. NULL // no inserted strings
  850. );
  851. if (nChars == 0)
  852. {
  853. LocalFree(lpParmBuffer);
  854. lpParmBuffer = NULL;
  855. }
  856. }
  857. }
  858. if ( lpParmBuffer )
  859. {
  860. try
  861. {
  862. DWORD nParmSize = pwszEnd - *ppwszReplacement;
  863. hr = ReplaceSubStr (
  864. lpParmBuffer,
  865. ppwszBuf,
  866. nOffset,
  867. nParmSize,
  868. ppwszReplacement,
  869. pulSize
  870. );
  871. }
  872. catch ( ... )
  873. {
  874. if ( lpParmBuffer )
  875. {
  876. LocalFree(lpParmBuffer);
  877. lpParmBuffer = NULL;
  878. }
  879. throw;
  880. }
  881. LocalFree(lpParmBuffer);
  882. lpParmBuffer = NULL;
  883. }
  884. else
  885. {
  886. hr = E_INVALIDARG;
  887. // move past whole parameter
  888. *ppwszReplacement = pwszEnd;
  889. }
  890. }
  891. return hr;
  892. }
  893. //+--------------------------------------------------------------------------
  894. //
  895. // Function: ReplaceSubStr
  896. //
  897. // Synopsis: Replace the characters from *[ppwszInsertPoint] to just
  898. // before [pwszSubStrEnd] with the string [pwszToInsert].
  899. //
  900. // Arguments: [pwszToInsert] - string to insert; may be L"" but not NULL.
  901. // [ppwszBuf] - buffer in which insertion occurs
  902. // [ulOffset] - point in *[ppwszBuf] to insert
  903. // [ulCharsOld] - number of chars to replace
  904. // [pulSize] - number of chars replaced
  905. //
  906. // Returns: S_OK
  907. // E_INVALIDARG
  908. //
  909. // Modifies: [ppwszBuf], [pptrReplacement]
  910. //
  911. // Notes: The substring to be replaced must be > 0 chars in length.
  912. //
  913. // The replacement string can be >= 0 chars.
  914. //
  915. // Therefore if the substring to replace is "%%12" and the
  916. // string to insert is "C:", on exit *[pcchRemain] will have
  917. // been incremented by 2.
  918. //
  919. // If there are insufficient characters remaining to replace
  920. // the substring with the insert string, reallocates the
  921. // buffer.
  922. //
  923. //---------------------------------------------------------------------------
  924. HRESULT CEventlogRecord::ReplaceSubStr (
  925. LPCWSTR pwszToInsert,
  926. LPWSTR *ppwszBuf,
  927. ULONG nOffset,
  928. ULONG nCharsOld,
  929. LPWSTR *pptrReplacement,
  930. ULONG *pulSize
  931. )
  932. {
  933. HRESULT hr = E_INVALIDARG;
  934. try
  935. {
  936. if ( pwszToInsert )
  937. {
  938. ULONG nChars = wcslen(pwszToInsert);
  939. UINT nStrSize = wcslen(*ppwszBuf)+1; // calculate original length
  940. UINT nNewSize = nStrSize+nChars-nCharsOld; // calculate new length
  941. wchar_t* tmp = *ppwszBuf;
  942. //
  943. // do we need to reallocate?
  944. //
  945. if (nNewSize > nStrSize)
  946. {
  947. tmp = new wchar_t[nNewSize]; // allocate new buffer
  948. if ( tmp == NULL ) // there is exception raisen in current implementation
  949. {
  950. hr = E_OUTOFMEMORY;
  951. *pptrReplacement -= 1; // get back to % as memory could get back
  952. }
  953. else
  954. {
  955. StringCchCopyW ( tmp, nNewSize, *ppwszBuf );
  956. delete [] *ppwszBuf;
  957. *ppwszBuf = tmp;
  958. hr = S_FALSE;
  959. }
  960. }
  961. else
  962. {
  963. hr = S_FALSE;
  964. }
  965. if ( SUCCEEDED ( hr ) )
  966. {
  967. *pptrReplacement = *ppwszBuf + nOffset; // point to start of current % (we are replacing)
  968. nStrSize = wcslen(*pptrReplacement)-nCharsOld+1; // calculate length of remainder of string
  969. //
  970. // perform move
  971. //
  972. memmove((void *)(*pptrReplacement+nChars), // destination address
  973. (void *)(*pptrReplacement+nCharsOld), // source address
  974. nStrSize*sizeof(wchar_t)); // amount of data to move
  975. memmove((void *)*pptrReplacement, // destination address
  976. (void *)pwszToInsert, // source address
  977. nChars*sizeof(wchar_t)); // amount of data to move
  978. *pulSize += ( nChars + 1 );
  979. hr = S_OK;
  980. }
  981. }
  982. }
  983. catch ( ... )
  984. {
  985. if (*ppwszBuf)
  986. {
  987. delete [] *ppwszBuf;
  988. *ppwszBuf = NULL;
  989. }
  990. throw;
  991. }
  992. return hr;
  993. }
  994. CStringW CEventlogRecord::GetUser(PSID userSid)
  995. {
  996. CStringW retVal;
  997. BOOL bFound = FALSE;
  998. MyPSID usrSID(userSid);
  999. {
  1000. ScopeLock<CSIDMap> sl(sm_usersMap);
  1001. if (!sm_usersMap.IsEmpty() && sm_usersMap.Lookup(usrSID, retVal))
  1002. {
  1003. bFound = TRUE;
  1004. }
  1005. }
  1006. if (!bFound)
  1007. {
  1008. DWORD dwVersion = GetVersion();
  1009. if ( (4 < (DWORD)(LOBYTE(LOWORD(dwVersion))))
  1010. || ObtainedSerialAccess(CNTEventProvider::g_secMutex) )
  1011. {
  1012. wchar_t szDomBuff[MAX_PATH];
  1013. wchar_t szUsrBuff[MAX_PATH];
  1014. DWORD domBuffLen = MAX_PATH;
  1015. DWORD usrBuffLen = MAX_PATH;
  1016. SID_NAME_USE snu;
  1017. if (LookupAccountSid( // lookup account name
  1018. NULL, // system to lookup account on
  1019. userSid, // pointer to SID for this account
  1020. szUsrBuff, // return account name in this buffer
  1021. &usrBuffLen, // pointer to size of account name returned
  1022. szDomBuff, // domain where account was found
  1023. &domBuffLen, //pointer to size of domain name
  1024. &snu)) // sid name use field pointer
  1025. {
  1026. retVal = szDomBuff;
  1027. retVal += L'\\';
  1028. retVal += szUsrBuff;
  1029. }
  1030. else
  1031. {
  1032. LONG lasterr = GetLastError();
  1033. DebugOut(
  1034. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1035. _T(__FILE__),__LINE__,
  1036. L"CEventlogRecord::GetUser:API (LookupAccountSid) failed with %lx\r\n",
  1037. lasterr
  1038. ) ;
  1039. )
  1040. }
  1041. if ( 5 > (DWORD)(LOBYTE(LOWORD(dwVersion))) )
  1042. {
  1043. ReleaseSerialAccess(CNTEventProvider::g_secMutex);
  1044. }
  1045. }
  1046. else
  1047. {
  1048. DebugOut(
  1049. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1050. _T(__FILE__),__LINE__,
  1051. L"CEventlogRecord::GetUser:Failed to get serial access to security APIs\r\n"
  1052. ) ;
  1053. )
  1054. }
  1055. //regardless of error enter this into map so we
  1056. //don't look up this PSID again
  1057. {
  1058. ScopeLock<CSIDMap> sl(sm_usersMap);
  1059. CStringW LookretVal;
  1060. if (!sm_usersMap.IsEmpty() && sm_usersMap.Lookup(usrSID, LookretVal))
  1061. {
  1062. return LookretVal;
  1063. }
  1064. else
  1065. {
  1066. DWORD sidlen = GetLengthSid(userSid);
  1067. MyPSID key;
  1068. key.m_SID = (PSID) new UCHAR[sidlen];
  1069. CopySid(sidlen, key.m_SID, userSid);
  1070. sm_usersMap[key] = retVal;
  1071. }
  1072. }
  1073. }
  1074. return retVal;
  1075. }
  1076. void CEventlogRecord::EmptyUsersMap()
  1077. {
  1078. if (sm_usersMap.Lock())
  1079. {
  1080. sm_usersMap.RemoveAll();
  1081. sm_usersMap.Unlock();
  1082. }
  1083. }
  1084. HINSTANCE CEventlogRecord::GetDll(CStringW path)
  1085. {
  1086. HINSTANCE retVal = NULL;
  1087. CStringW key(path);
  1088. key.MakeUpper();
  1089. BOOL bFound = FALSE;
  1090. {
  1091. ScopeLock<CDllMap> sl(sm_dllMap);
  1092. if (!sm_dllMap.IsEmpty() && sm_dllMap.Lookup(key, retVal))
  1093. {
  1094. bFound = TRUE;
  1095. }
  1096. }
  1097. if (!bFound)
  1098. {
  1099. retVal = LoadLibraryEx(path, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
  1100. if (retVal == NULL)
  1101. {
  1102. DebugOut(
  1103. DWORD lasterr = GetLastError();
  1104. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1105. _T(__FILE__),__LINE__,
  1106. L"CEventlogRecord::GetDll:API (LoadLibraryEx) failed with %lx for %s\r\n",
  1107. lasterr, path
  1108. ) ;
  1109. )
  1110. }
  1111. else
  1112. {
  1113. HINSTANCE LookretVal = NULL;
  1114. ScopeLock<CDllMap> sl(sm_dllMap);
  1115. if (!sm_dllMap.IsEmpty() && sm_dllMap.Lookup(key, LookretVal))
  1116. {
  1117. FreeLibrary(retVal); //release the ref count as we increased it by one as above.
  1118. return LookretVal;
  1119. } else {
  1120. sm_dllMap[key] = retVal;
  1121. }
  1122. }
  1123. }
  1124. return retVal;
  1125. }
  1126. void CEventlogRecord::EmptyDllMap()
  1127. {
  1128. if (sm_dllMap.Lock())
  1129. {
  1130. sm_dllMap.RemoveAll();
  1131. sm_dllMap.Unlock();
  1132. }
  1133. }
  1134. void CEventlogRecord::SetMessage()
  1135. {
  1136. HINSTANCE hMsgModule;
  1137. wchar_t* lpBuffer = NULL;
  1138. CStringW log(EVENTLOG_BASE);
  1139. log += L"\\";
  1140. log += m_Logfile;
  1141. HKEY hkResult;
  1142. LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, log, 0, KEY_READ, &hkResult);
  1143. if (status != ERROR_SUCCESS)
  1144. {
  1145. DebugOut(
  1146. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1147. _T(__FILE__),__LINE__,
  1148. L"CEventlogRecord::SetMessage:API (RegOpenKeyEx) failed with %lx for %s\r\n",
  1149. status, log
  1150. ) ;
  1151. )
  1152. return;
  1153. }
  1154. ON_BLOCK_EXIT ( RegCloseKey, hkResult ) ;
  1155. DWORD dwType;
  1156. wchar_t* prim = NULL;
  1157. prim = new wchar_t[MAX_PATH];
  1158. DWORD datalen = MAX_PATH * sizeof(wchar_t);
  1159. status = RegQueryValueEx(hkResult, PRIM_MODULE, 0, &dwType, (LPBYTE)prim, &datalen);
  1160. if (status != ERROR_SUCCESS)
  1161. {
  1162. if (status == ERROR_MORE_DATA)
  1163. {
  1164. delete [] prim;
  1165. prim = new wchar_t[datalen];
  1166. status = RegQueryValueEx(hkResult, PRIM_MODULE, 0, &dwType, (LPBYTE)prim, &datalen);
  1167. }
  1168. }
  1169. HKEY hkPrimary = NULL;
  1170. HKEY hkSource = NULL;
  1171. wmilib::auto_buffer < wchar_t > Smartprim ( prim ) ;
  1172. if ( ERROR_SUCCESS == status && dwType == REG_SZ )
  1173. {
  1174. // this is path to primary log
  1175. CStringW primLog = log + L"\\";
  1176. primLog += prim;
  1177. // open a registry for primary event log key
  1178. if ((_wcsicmp(m_SourceName, prim)) != 0)
  1179. {
  1180. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, primLog, 0, KEY_READ, &hkPrimary);
  1181. }
  1182. }
  1183. ON_BLOCK_EXIT ( RegCloseKey, hkPrimary ) ;
  1184. // this is path to source log
  1185. CStringW sourceLog = log + L"\\";
  1186. sourceLog += m_SourceName;
  1187. // check to see there is a registry for source
  1188. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sourceLog, 0, KEY_READ, &hkSource);
  1189. if (status != ERROR_SUCCESS)
  1190. {
  1191. DebugOut(
  1192. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1193. _T(__FILE__),__LINE__,
  1194. L"CEventlogRecord::SetMessage:API (RegOpenKeyEx) failed with %lx for %s\r\n",
  1195. status, log
  1196. ) ;
  1197. )
  1198. return;
  1199. }
  1200. ON_BLOCK_EXIT ( RegCloseKey, hkSource ) ;
  1201. // get category file
  1202. CStringW cat_modname = CEventLogFile::GetFileName(hkSource, CAT_MODULE);
  1203. if (cat_modname.IsEmpty())
  1204. {
  1205. if ( hkPrimary )
  1206. {
  1207. // try primary event log key as source doesn't have category
  1208. cat_modname = CEventLogFile::GetFileName(hkPrimary, CAT_MODULE);
  1209. }
  1210. }
  1211. // workout category and category string if possible
  1212. if (!cat_modname.IsEmpty())
  1213. {
  1214. hMsgModule = GetDll(cat_modname);
  1215. if (hMsgModule != NULL)
  1216. {
  1217. if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | // let api build buffer
  1218. FORMAT_MESSAGE_IGNORE_INSERTS | // indicate no string inserts
  1219. FORMAT_MESSAGE_FROM_HMODULE | // look thru message DLL
  1220. FORMAT_MESSAGE_MAX_WIDTH_MASK ,
  1221. (LPVOID) hMsgModule, // handle to message module
  1222. m_Category, // message number to get
  1223. (ULONG) NULL, // specify no language
  1224. (LPWSTR) &lpBuffer, // address for buffer pointer
  1225. 80, // minimum space to allocate
  1226. NULL))
  1227. {
  1228. m_CategoryString = lpBuffer;
  1229. m_CategoryString.TrimRight();
  1230. LocalFree(lpBuffer);
  1231. }
  1232. else
  1233. {
  1234. DWORD lasterr = GetLastError();
  1235. DebugOut(
  1236. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1237. _T(__FILE__),__LINE__,
  1238. L"CEventlogRecord::SetMessage:API (FormatMessage) failed with %lx\r\n",
  1239. lasterr
  1240. ) ;
  1241. )
  1242. }
  1243. }
  1244. }
  1245. // get event message file
  1246. CStringW* names;
  1247. DWORD count = CEventLogFile::GetFileNames(hkSource, &names);
  1248. if ( !count )
  1249. {
  1250. if ( hkPrimary )
  1251. {
  1252. // try primary event log key as source doesn't have event message file
  1253. count = CEventLogFile::GetFileNames(hkPrimary, &names);
  1254. }
  1255. }
  1256. // work out event messages
  1257. if (count != 0)
  1258. {
  1259. for (int x = 0; x < count; x++)
  1260. {
  1261. hMsgModule = GetDll(names[x]);
  1262. if (hMsgModule != NULL)
  1263. {
  1264. if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | // let api build buffer
  1265. FORMAT_MESSAGE_ARGUMENT_ARRAY | // indicate an array of string inserts
  1266. FORMAT_MESSAGE_IGNORE_INSERTS | // indicate no string inserts
  1267. FORMAT_MESSAGE_FROM_HMODULE, // look thru message DLL
  1268. (LPVOID) hMsgModule, // handle to message module
  1269. m_EvtID, // message number to get
  1270. (ULONG) NULL, // specify no language
  1271. (LPWSTR) &lpBuffer, // address for buffer pointer
  1272. 80, // minimum space to allocate
  1273. NULL))
  1274. {
  1275. m_Message = lpBuffer;
  1276. LocalFree(lpBuffer);
  1277. break;
  1278. }
  1279. else
  1280. {
  1281. DWORD lasterr = GetLastError();
  1282. DebugOut(
  1283. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1284. _T(__FILE__),__LINE__,
  1285. L"CEventlogRecord::SetMessage:API (FormatMessage) failed with %lx\r\n",
  1286. lasterr
  1287. ) ;
  1288. )
  1289. }
  1290. }
  1291. }
  1292. delete [] names;
  1293. }
  1294. if (m_NumStrs != 0)
  1295. {
  1296. CheckInsertionStrings(hkSource, hkPrimary);
  1297. }
  1298. }
  1299. void CEventlogRecord::SetTimeStr(CStringW& str, DWORD timeVal)
  1300. {
  1301. WBEMTime tmpTime((time_t)timeVal);
  1302. BSTR tStr = tmpTime.GetDMTF(TRUE);
  1303. str = tStr;
  1304. SysFreeString(tStr);
  1305. }
  1306. void CEventlogRecord::SetType(WORD type)
  1307. {
  1308. switch (type)
  1309. {
  1310. case 0:
  1311. {
  1312. m_Type = m_TypeArray[0];
  1313. m_EvtType = 0;
  1314. break;
  1315. }
  1316. case 1:
  1317. {
  1318. m_Type = m_TypeArray[1];
  1319. m_EvtType = 1;
  1320. break;
  1321. }
  1322. case 2:
  1323. {
  1324. m_Type = m_TypeArray[2];
  1325. m_EvtType = 2;
  1326. break;
  1327. }
  1328. case 4:
  1329. {
  1330. m_Type = m_TypeArray[3];
  1331. m_EvtType = 3;
  1332. break;
  1333. }
  1334. case 8:
  1335. {
  1336. m_Type = m_TypeArray[4];
  1337. m_EvtType = 4;
  1338. break;
  1339. }
  1340. case 16:
  1341. {
  1342. m_Type = m_TypeArray[5];
  1343. m_EvtType = 5;
  1344. break;
  1345. }
  1346. default:
  1347. {
  1348. DebugOut(
  1349. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1350. _T(__FILE__),__LINE__,
  1351. L"CEventlogRecord::SetType:Unknown type %lx\r\n",
  1352. (long)type
  1353. ) ;
  1354. )
  1355. break;
  1356. }
  1357. }
  1358. #if 0
  1359. if (m_Type.IsEmpty())
  1360. {
  1361. wchar_t* buff = m_Type.GetBuffer(20);
  1362. _ultow((ULONG)type, buff, 10);
  1363. m_Type.ReleaseBuffer();
  1364. }
  1365. #endif
  1366. }
  1367. ULONG CEventlogRecord::GetIndex(wchar_t* indexStr, BOOL* bError)
  1368. {
  1369. int val = _wtoi(indexStr);
  1370. *bError = FALSE;
  1371. ULONG index = 0;
  1372. switch (val)
  1373. {
  1374. case EVENTLOG_SUCCESS: //0
  1375. {
  1376. index = 0;
  1377. break;
  1378. }
  1379. case EVENTLOG_ERROR_TYPE: //1
  1380. {
  1381. index = 1;
  1382. break;
  1383. }
  1384. case EVENTLOG_WARNING_TYPE: //2
  1385. {
  1386. index = 2;
  1387. break;
  1388. }
  1389. case EVENTLOG_INFORMATION_TYPE: //4
  1390. {
  1391. index = 3;
  1392. break;
  1393. }
  1394. case EVENTLOG_AUDIT_SUCCESS: //8
  1395. {
  1396. index = 4;
  1397. break;
  1398. }
  1399. case EVENTLOG_AUDIT_FAILURE: //16
  1400. {
  1401. index = 5;
  1402. break;
  1403. }
  1404. default:
  1405. {
  1406. *bError = TRUE;
  1407. DebugOut(
  1408. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1409. _T(__FILE__),__LINE__,
  1410. L"CEventlogRecord::Index:Unknown index %lx\r\n",
  1411. val
  1412. ) ;
  1413. )
  1414. }
  1415. }
  1416. return index;
  1417. }
  1418. BOOL CEventlogRecord::SetEnumArray(IWbemClassObject* pClass, wchar_t* propname, CStringW* strArray, ULONG strArrayLen, GetIndexFunc IndexFunc)
  1419. {
  1420. BOOL retVal = FALSE;
  1421. IWbemQualifierSet* pQuals = NULL;
  1422. if (SUCCEEDED(pClass->GetPropertyQualifierSet(propname, &pQuals)))
  1423. {
  1424. VARIANT vVals;
  1425. if (SUCCEEDED(pQuals->Get(EVT_ENUM_QUAL, 0, &vVals, NULL)))
  1426. {
  1427. VARIANT vInds;
  1428. if (SUCCEEDED(pQuals->Get(EVT_MAP_QUAL, 0, &vInds, NULL)))
  1429. {
  1430. if ((vInds.vt == vVals.vt) && (vInds.vt == (VT_BSTR | VT_ARRAY)) &&
  1431. (SafeArrayGetDim(vInds.parray) == SafeArrayGetDim(vVals.parray)) &&
  1432. (SafeArrayGetDim(vVals.parray) == 1) && (vInds.parray->rgsabound[0].cElements == strArrayLen) &&
  1433. (vInds.parray->rgsabound[0].cElements == vVals.parray->rgsabound[0].cElements) )
  1434. {
  1435. BSTR *strInds = NULL;
  1436. if (SUCCEEDED(SafeArrayAccessData(vInds.parray, (void **)&strInds)) )
  1437. {
  1438. BSTR *strVals = NULL;
  1439. if (SUCCEEDED(SafeArrayAccessData(vVals.parray, (void **)&strVals)) )
  1440. {
  1441. BOOL bErr = FALSE;
  1442. retVal = TRUE;
  1443. for (ULONG x = 0; x < strArrayLen; x++)
  1444. {
  1445. ULONG index = IndexFunc(strInds[x], &bErr);
  1446. if (!bErr)
  1447. {
  1448. if (strArray[index].IsEmpty())
  1449. {
  1450. strArray[index] = strVals[x];
  1451. }
  1452. }
  1453. else
  1454. {
  1455. retVal = FALSE;
  1456. break;
  1457. }
  1458. }
  1459. SafeArrayUnaccessData(vVals.parray);
  1460. }
  1461. SafeArrayUnaccessData(vInds.parray);
  1462. }
  1463. }
  1464. VariantClear(&vInds);
  1465. }
  1466. VariantClear(&vVals);
  1467. }
  1468. else
  1469. {
  1470. DebugOut(
  1471. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1472. _T(__FILE__),__LINE__,
  1473. L"CEventlogRecord::SetEnumArray:Failed to get enumeration qualifier.\r\n"
  1474. ) ;
  1475. )
  1476. }
  1477. pQuals->Release();
  1478. }
  1479. else
  1480. {
  1481. DebugOut(
  1482. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1483. _T(__FILE__),__LINE__,
  1484. L"CEventlogRecord::SetEnumArray:Failed to get qualifier set for enumeration.\r\n"
  1485. ) ;
  1486. )
  1487. }
  1488. return retVal;
  1489. }
  1490. BOOL CEventlogRecord::GetInstance()
  1491. {
  1492. BSTR path = SysAllocString(NTEVT_CLASS);
  1493. if ( NULL == path )
  1494. {
  1495. return FALSE ;
  1496. }
  1497. if (m_nspace != NULL)
  1498. {
  1499. if (!WbemTaskObject::GetClassObject(path, FALSE, m_nspace, NULL, &m_pClass ))
  1500. {
  1501. m_pClass = NULL;
  1502. DebugOut(
  1503. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1504. _T(__FILE__),__LINE__,
  1505. L"CEventlogRecord::GetInstance:Failed to get Class object\r\n"
  1506. ) ;
  1507. )
  1508. }
  1509. if (!WbemTaskObject::GetClassObject(path, TRUE, m_nspace, NULL, &m_pAClass ))
  1510. {
  1511. m_pAClass = NULL;
  1512. DebugOut(
  1513. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1514. _T(__FILE__),__LINE__,
  1515. L"CEventlogRecord::GetInstance:Failed to get Amended Class object\r\n"
  1516. ) ;
  1517. )
  1518. }
  1519. m_nspace->Release();
  1520. m_nspace = NULL;
  1521. }
  1522. if (m_pClass != NULL)
  1523. {
  1524. m_pClass->SpawnInstance(0, &m_Obj);
  1525. if (m_pAClass)
  1526. {
  1527. SetEnumArray(m_pAClass, TYPE_PROP,(CStringW*)m_TypeArray, TYPE_ARRAY_LEN, (GetIndexFunc)GetIndex);
  1528. m_pAClass->Release();
  1529. m_pAClass = NULL;
  1530. }
  1531. m_pClass->Release();
  1532. m_pClass = NULL;
  1533. }
  1534. SysFreeString(path);
  1535. if (m_Obj != NULL)
  1536. {
  1537. return TRUE;
  1538. }
  1539. DebugOut(
  1540. CNTEventProvider::g_NTEvtDebugLog->WriteFileAndLine (
  1541. _T(__FILE__),__LINE__,
  1542. L"CEventlogRecord::GetInstance:Failed to spawn instance\r\n"
  1543. ) ;
  1544. )
  1545. return FALSE;
  1546. }
  1547. class CDsBindingHandle
  1548. {
  1549. public:
  1550. // initally unbound
  1551. CDsBindingHandle()
  1552. :
  1553. m_hDS(0)
  1554. {
  1555. }
  1556. ~CDsBindingHandle()
  1557. {
  1558. if ( m_hDS )
  1559. {
  1560. DsUnBind(&m_hDS);
  1561. }
  1562. }
  1563. // only re-binds if the dc name differs...
  1564. DWORD Bind(LPCWSTR strDcName);
  1565. // don't call DsUnBind on an instance of this class: you'll only regret
  1566. // it later. Let the dtor do the unbind.
  1567. operator HANDLE()
  1568. {
  1569. return m_hDS;
  1570. }
  1571. DWORD CrackGuid(LPCWSTR pwzGuid, CStringW &strResult);
  1572. private:
  1573. HANDLE m_hDS;
  1574. };
  1575. DWORD CDsBindingHandle::Bind(LPCWSTR strDcName)
  1576. {
  1577. DWORD err = NO_ERROR;
  1578. if (m_hDS)
  1579. {
  1580. DsUnBind(&m_hDS);
  1581. m_hDS = NULL;
  1582. }
  1583. //
  1584. // NULL is used for connecting GC
  1585. //
  1586. LPCWSTR szDcName = NULL ;
  1587. if ( NULL != *strDcName )
  1588. {
  1589. szDcName = strDcName ;
  1590. }
  1591. err = DsBind ( szDcName, 0, &m_hDS ) ;
  1592. if (err != NO_ERROR)
  1593. {
  1594. m_hDS = NULL;
  1595. }
  1596. return err;
  1597. }
  1598. DWORD CDsBindingHandle::CrackGuid(LPCWSTR pwzGuid, CStringW &strResult)
  1599. {
  1600. DWORD err = ERROR;
  1601. if( NULL == m_hDS ) return err;
  1602. strResult.Empty();
  1603. DS_NAME_RESULT* name_result = 0;
  1604. err = DsCrackNames(
  1605. m_hDS,
  1606. DS_NAME_NO_FLAGS,
  1607. DS_UNIQUE_ID_NAME,
  1608. DS_FQDN_1779_NAME,
  1609. 1, // only 1 name to crack
  1610. &pwzGuid,
  1611. &name_result);
  1612. if (err == NO_ERROR && name_result)
  1613. {
  1614. DS_NAME_RESULT_ITEM* item = name_result->rItems;
  1615. if (item)
  1616. {
  1617. // the API may return success, but each cracked name also carries
  1618. // an error code, which we effectively check by checking the name
  1619. // field for a value.
  1620. if (item->pName)
  1621. {
  1622. strResult = item->pName;
  1623. }
  1624. }
  1625. DsFreeNameResult(name_result);
  1626. }
  1627. return err;
  1628. }
  1629. CStringW CEventlogRecord::GetMappedGUID(LPCWSTR strDcName, LPCWSTR strGuid)
  1630. {
  1631. GUID guid;
  1632. CDsBindingHandle s_hDS;
  1633. if (RPC_S_OK == UuidFromString((LPWSTR)strGuid, &guid))
  1634. {
  1635. return CStringW();
  1636. }
  1637. CStringW strResult;
  1638. ULONG ulError = NO_ERROR;
  1639. do
  1640. {
  1641. ulError = s_hDS.Bind(strDcName);
  1642. if (ulError != NO_ERROR)
  1643. {
  1644. break;
  1645. }
  1646. DS_SCHEMA_GUID_MAP* guidmap = 0;
  1647. ulError = DsMapSchemaGuids(s_hDS, 1, &guid, &guidmap);
  1648. if (ulError != NO_ERROR)
  1649. {
  1650. break;
  1651. }
  1652. if (guidmap->pName)
  1653. {
  1654. strResult = guidmap->pName;
  1655. }
  1656. DsFreeSchemaGuidMap(guidmap);
  1657. if (strResult.GetLength())
  1658. {
  1659. // the guid mapped as a schema guid: we're done
  1660. break;
  1661. }
  1662. // the guid is not a schema guid. Proabably an object guid.
  1663. ulError = s_hDS.CrackGuid(strGuid, strResult);
  1664. }
  1665. while (0);
  1666. do
  1667. {
  1668. //
  1669. // If we've got a string from the guid already, we're done.
  1670. //
  1671. if (strResult.GetLength())
  1672. {
  1673. break;
  1674. }
  1675. //
  1676. // one last try. in this case, we bind to a GC to try to crack the
  1677. // name.
  1678. // empty string implies GC
  1679. if (s_hDS.Bind(L"") != NO_ERROR)
  1680. {
  1681. break;
  1682. }
  1683. ulError = s_hDS.CrackGuid(strGuid, strResult);
  1684. }
  1685. while (0);
  1686. return strResult;
  1687. }