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.

519 lines
13 KiB

  1. f/*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module evtlogwriter.cxx | Implementation of the Event Log Writer
  6. @end
  7. Author:
  8. Stefan Steiner [SSteiner] 07/26/2001
  9. TBD:
  10. Revision History:
  11. Name Date Comments
  12. ssteiner 07/26/2001 created
  13. --*/
  14. #include "stdafx.h"
  15. #include "vs_idl.hxx"
  16. #include "vs_hash.hxx"
  17. #include <vswriter.h>
  18. #include <Sddl.h>
  19. #include "vs_seh.hxx"
  20. #include "vs_trace.hxx"
  21. #include "vs_debug.hxx"
  22. #include "vs_reg.hxx"
  23. #include "evtlogwriter.hxx"
  24. #include "allerror.h"
  25. ////////////////////////////////////////////////////////////////////////
  26. // Standard foo for file name aliasing. This code block must be after
  27. // all includes of VSS header files.
  28. //
  29. #ifdef VSS_FILE_ALIAS
  30. #undef VSS_FILE_ALIAS
  31. #endif
  32. #define VSS_FILE_ALIAS "WRTEVTRC"
  33. //
  34. ////////////////////////////////////////////////////////////////////////
  35. static GUID s_writerId =
  36. {
  37. 0xeee8c692, 0x67ed, 0x4250, 0x8d, 0x86, 0x39, 0x6, 0x3, 0x7, 0xd, 0x00
  38. };
  39. // The display name of the Event Log writer.
  40. static LPCWSTR s_wszWriterName = L"Event Log Writer";
  41. // The file group component name for the Event Log
  42. static LPCWSTR s_wszComponentName = L"Event Logs";
  43. // The Registry key that contains event-log information
  44. static LPCWSTR s_wszLogKey = L"SYSTEM\\CurrentControlSet\\Services\\Eventlog";
  45. // The value field that contains the the event-log file
  46. static LPCWSTR s_wszLogFile = L"File";
  47. // The location of where the Event Log will be copied.
  48. static CBsString s_cwsEventLogsTargetDir = ROOT_BACKUP_DIR SERVICE_STATE_SUBDIR L"\\EventLogs";
  49. // The location of the Event Log
  50. static CBsString s_cwsSystemEventLogDir = L"%SystemRoot%\\system32\\config";
  51. // The mask specifying which files to exclude from backup
  52. static CBsString s_cwsSystemEventLogFiles = L"*.evt";
  53. // Class wide member variables
  54. CEventLogWriter *CEventLogWriter::sm_pWriter;
  55. HRESULT CEventLogWriter::sm_hrInitialize;
  56. HRESULT STDMETHODCALLTYPE CEventLogWriter::Initialize()
  57. {
  58. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::Initialize");
  59. try
  60. {
  61. ft.hr = CVssWriter::Initialize
  62. (
  63. s_writerId,
  64. s_wszWriterName,
  65. VSS_UT_SYSTEMSERVICE,
  66. VSS_ST_OTHER,
  67. VSS_APP_SYSTEM,
  68. 60000
  69. );
  70. if (ft.HrFailed())
  71. ft.Throw
  72. (
  73. VSSDBG_WRITER,
  74. E_UNEXPECTED,
  75. L"Failed to initialize the Event Log writer. hr = 0x%08lx",
  76. ft.hr
  77. );
  78. ft.hr = Subscribe();
  79. if (ft.HrFailed())
  80. ft.Throw
  81. (
  82. VSSDBG_WRITER,
  83. E_UNEXPECTED,
  84. L"Subscribing the Event Log server writer failed. hr = %0x08lx",
  85. ft.hr
  86. );
  87. }
  88. VSS_STANDARD_CATCH(ft)
  89. return ft.hr;
  90. }
  91. HRESULT STDMETHODCALLTYPE CEventLogWriter::Uninitialize()
  92. {
  93. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::Uninitialize");
  94. return Unsubscribe();
  95. }
  96. // handle request for WRITER_METADATA
  97. // implements CVssWriter::OnIdentify
  98. bool STDMETHODCALLTYPE CEventLogWriter::OnIdentify(IVssCreateWriterMetadata *pMetadata)
  99. {
  100. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnIdentify");
  101. try
  102. {
  103. //
  104. // Set the restore method for the writer
  105. //
  106. ft.hr = pMetadata->SetRestoreMethod
  107. (
  108. VSS_RME_RESTORE_AT_REBOOT,
  109. NULL,
  110. NULL,
  111. VSS_WRE_NEVER,
  112. true
  113. );
  114. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
  115. //
  116. // Add the one file component
  117. //
  118. ft.hr = pMetadata->AddComponent
  119. (
  120. VSS_CT_FILEGROUP,
  121. NULL,
  122. s_wszComponentName,
  123. s_wszComponentName,
  124. NULL, // icon
  125. 0,
  126. false,
  127. false,
  128. true
  129. );
  130. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddComponent");
  131. AddExcludes(pMetadata);
  132. ScanLogs();
  133. AddLogs(pMetadata);
  134. }
  135. VSS_STANDARD_CATCH(ft)
  136. TranslateWriterError(ft.hr);
  137. return ft.HrSucceeded();
  138. }
  139. bool STDMETHODCALLTYPE CEventLogWriter::OnPrepareSnapshot()
  140. {
  141. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnPrepareSnapshot");
  142. try
  143. {
  144. CBsString cwsExpanded;
  145. if (!cwsExpanded.ExpandEnvironmentStrings(s_cwsEventLogsTargetDir))
  146. {
  147. ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
  148. L"CBsString::ExpandEnvironmentStrings");
  149. }
  150. // make sure that we don't backup up old stuff in the event log backup dir
  151. ft.hr = ::RemoveDirectoryTree(cwsExpanded);
  152. ft.CheckForErrorInternal(VSSDBG_WRITER, L"::RemoveDirectoryTree");
  153. ft.hr = ::CreateTargetPath(cwsExpanded);
  154. ft.CheckForError(VSSDBG_WRITER, L"::CreateTargetPath");
  155. if (IsPathAffected(s_cwsSystemEventLogDir))
  156. BackupLogs();
  157. }
  158. VSS_STANDARD_CATCH( ft );
  159. TranslateWriterError(ft.hr);
  160. ft.Trace(VSSDBG_WRITER, L"CEventLogWriter returning with hresult 0x%08lx", ft.hr);
  161. return ft.HrSucceeded();
  162. }
  163. bool STDMETHODCALLTYPE CEventLogWriter::OnFreeze()
  164. {
  165. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnFreeze");
  166. return ft.HrSucceeded();
  167. }
  168. bool STDMETHODCALLTYPE CEventLogWriter::OnThaw()
  169. {
  170. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnThaw");
  171. return ft.HrSucceeded();
  172. }
  173. bool STDMETHODCALLTYPE CEventLogWriter::OnAbort()
  174. {
  175. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnAbort");
  176. return ft.HrSucceeded();
  177. }
  178. bool CEventLogWriter::IsPathInSnapshot(const WCHAR *wszPath) throw()
  179. {
  180. return IsPathAffected(wszPath);
  181. }
  182. // translate a sql writer error code into a writer error
  183. void CEventLogWriter::TranslateWriterError( HRESULT hr )
  184. {
  185. switch(hr)
  186. {
  187. default:
  188. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  189. break;
  190. case S_OK:
  191. break;
  192. case E_OUTOFMEMORY:
  193. case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
  194. case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES):
  195. case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
  196. case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES):
  197. SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES);
  198. break;
  199. }
  200. }
  201. // Creates one instance of the Event Log writer class. If one already exists, it simple returns.
  202. // static
  203. HRESULT CEventLogWriter::CreateWriter()
  204. {
  205. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::CreateWriter");
  206. if ( sm_pWriter != NULL )
  207. return S_OK;
  208. //
  209. // OK, spin up a thread to do the subscription in.
  210. //
  211. try
  212. {
  213. sm_pWriter = new CEventLogWriter;
  214. if (sm_pWriter == NULL)
  215. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Allocation of CEventLogWriter object failed.");
  216. DWORD tid;
  217. HANDLE hThread = ::CreateThread
  218. (
  219. NULL,
  220. 256* 1024,
  221. InitializeThreadFunc,
  222. NULL,
  223. 0,
  224. &tid
  225. );
  226. if (hThread == NULL)
  227. ft.Throw
  228. (
  229. VSSDBG_WRITER,
  230. E_UNEXPECTED,
  231. L"CreateThread failed with error %d",
  232. ::GetLastError()
  233. );
  234. // wait for thread to complete
  235. ::WaitForSingleObject( hThread, INFINITE );
  236. ::CloseHandle( hThread );
  237. ft.hr = sm_hrInitialize;
  238. }
  239. VSS_STANDARD_CATCH(ft)
  240. if (ft.HrFailed() && sm_pWriter)
  241. {
  242. delete sm_pWriter;
  243. sm_pWriter = NULL;
  244. }
  245. return ft.hr;
  246. }
  247. void CEventLogWriter::FreeLogs()
  248. {
  249. // free event-log information
  250. for (int x = 0; x < m_eventLogs.GetSize(); x++)
  251. {
  252. ::VssFreeString(m_eventLogs[x].m_pwszName);
  253. ::VssFreeString(m_eventLogs[x].m_pwszFileName);
  254. }
  255. m_eventLogs.RemoveAll();
  256. }
  257. void CEventLogWriter::ScanLogs()
  258. {
  259. CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::ScanLogs");
  260. FreeLogs();
  261. // open the main registry key
  262. CVssRegistryKey hkeyEventLogList (KEY_READ);
  263. if (!hkeyEventLogList.Open(HKEY_LOCAL_MACHINE, s_wszLogKey))
  264. {
  265. ft.Trace (VSSDBG_WRITER, L"Failed to open registry key: %s", s_wszLogKey);
  266. return;
  267. }
  268. CVssRegistryKeyIterator iterator;
  269. iterator.Attach (hkeyEventLogList);
  270. // for each subkey corresponding to a log
  271. while (!iterator.IsEOF())
  272. {
  273. EventLog currentLog;
  274. // --- get the file entry
  275. CVssRegistryKey hkeyEventLog(KEY_QUERY_VALUE);
  276. if (!hkeyEventLog.Open(hkeyEventLogList.GetHandle(), iterator.GetCurrentKeyName()))
  277. {
  278. ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
  279. L"Failed to open registry entry for event log %s", iterator.GetCurrentKeyName());
  280. }
  281. CVssAutoPWSZ pwszFileName;
  282. hkeyEventLog.GetValue(s_wszLogFile, pwszFileName.GetRef(), false);
  283. if (pwszFileName.GetRef() == NULL)
  284. {
  285. ft.Trace(VSSDBG_WRITER,
  286. L"Error reading File value for event log %s", iterator.GetCurrentKeyName());
  287. iterator.MoveNext();
  288. continue;
  289. }
  290. // ensure that the name has at least a single \ in it
  291. if (wcschr(pwszFileName, DIR_SEP_CHAR) == NULL)
  292. {
  293. ft.Trace(VSSDBG_WRITER,
  294. L"Error in the File value for event log %s", iterator.GetCurrentKeyName());
  295. iterator.MoveNext();
  296. continue;
  297. }
  298. // --- get the name of the log
  299. CVssAutoPWSZ pwszName;
  300. if (!pwszName.CopyFrom(iterator.GetCurrentKeyName()))
  301. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to allocate memory for event log name");
  302. // -- add the information to the list
  303. currentLog.m_pwszFileName = pwszFileName;
  304. currentLog.m_pwszName = pwszName;
  305. if (!m_eventLogs.Add(currentLog))
  306. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to add entry to list");
  307. pwszFileName.Detach();
  308. pwszName.Detach();
  309. iterator.MoveNext();
  310. }
  311. }
  312. void CEventLogWriter::AddExcludes(IVssCreateWriterMetadata* pMetadata)
  313. {
  314. CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::AddExcludes");
  315. pMetadata->AddExcludeFiles(s_cwsSystemEventLogDir, s_cwsSystemEventLogFiles,
  316. false);
  317. }
  318. void CEventLogWriter::AddLogs(IVssCreateWriterMetadata* pMetadata)
  319. {
  320. CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::AddLogs");
  321. // add each log file to the component
  322. for (int x = 0; x < m_eventLogs.GetSize(); x++)
  323. {
  324. CVssAutoPWSZ pwszEventPath;
  325. if (!pwszEventPath.CopyFrom(m_eventLogs[x].m_pwszFileName))
  326. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to allocate memory for event log name");
  327. // --- seperate out the path, and add to the component
  328. VSS_PWSZ pwszEventFile = wcsrchr(pwszEventPath, DIR_SEP_CHAR);
  329. BS_ASSERT(pwszEventFile != NULL);
  330. *pwszEventFile = L'\0';
  331. ++pwszEventFile;
  332. ft.hr = pMetadata->AddFilesToFileGroup
  333. (NULL,
  334. s_wszComponentName,
  335. pwszEventPath,
  336. pwszEventFile,
  337. false,
  338. s_cwsEventLogsTargetDir
  339. );
  340. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
  341. }
  342. }
  343. void CEventLogWriter::BackupLogs()
  344. {
  345. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::BackupLogs");
  346. // back up each event log
  347. for (int x = 0; x < m_eventLogs.GetSize(); x++)
  348. {
  349. BS_ASSERT(m_eventLogs[x].m_pwszName != NULL);
  350. BS_ASSERT(m_eventLogs[x].m_pwszName != NULL);
  351. CVssAutoWin32EventLogHandle hLog =
  352. ::OpenEventLog(NULL, m_eventLogs[x].m_pwszName);
  353. if (hLog == NULL)
  354. {
  355. ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
  356. L"Failed to open event log %s. [0x%08lx]", m_eventLogs[x].m_pwszName, ::GetLastError());
  357. }
  358. // --- build up the path that we will back up to
  359. VSS_PWSZ pwszBackupFile = ::wcsrchr(m_eventLogs[x].m_pwszFileName, DIR_SEP_CHAR);
  360. BS_ASSERT(pwszBackupFile != NULL);
  361. CBsString cwsBackupPath;
  362. cwsBackupPath.ExpandEnvironmentStrings(s_cwsEventLogsTargetDir);
  363. cwsBackupPath += pwszBackupFile;
  364. // --- NOTE: There's a potential failure scenario here. If two different event logs have the same filename
  365. // --- in different directories, they will overwrite each other in the spit directory. This will be fixed when the
  366. // --- writer is altered to be an in-place writer
  367. if (::BackupEventLog(hLog, cwsBackupPath) == FALSE)
  368. {
  369. ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
  370. L"Failed to backup event log %s to %s. [0x%08lx]", m_eventLogs[x].m_pwszName,
  371. cwsBackupPath, ::GetLastError());
  372. }
  373. }
  374. }
  375. // static
  376. DWORD CEventLogWriter::InitializeThreadFunc(VOID *pv)
  377. {
  378. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::InitializeThreadFunc");
  379. BOOL fCoinitializeSucceeded = false;
  380. try
  381. {
  382. // intialize MTA thread
  383. ft.hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
  384. if (ft.HrFailed())
  385. ft.Throw
  386. (
  387. VSSDBG_WRITER,
  388. E_UNEXPECTED,
  389. L"CoInitializeEx failed 0x%08lx", ft.hr
  390. );
  391. fCoinitializeSucceeded = true;
  392. // Now initialize the base class and subscribe
  393. ft.hr = sm_pWriter->Initialize();
  394. }
  395. VSS_STANDARD_CATCH(ft)
  396. if (fCoinitializeSucceeded)
  397. CoUninitialize();
  398. sm_hrInitialize = ft.hr;
  399. return 0;
  400. UNREFERENCED_PARAMETER( pv );
  401. }
  402. // static
  403. void CEventLogWriter::DestroyWriter()
  404. {
  405. CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::DestroyWriter");
  406. if (sm_pWriter)
  407. {
  408. sm_pWriter->Uninitialize();
  409. delete sm_pWriter;
  410. sm_pWriter = NULL;
  411. }
  412. }