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.

495 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. autostart.c
  5. Abstract:
  6. Autostart wmi loggers.
  7. Takes arguments from tracing registry
  8. (This code may end up in wpp framework, hence Wpp prefix)
  9. Author:
  10. Gor Nishanov (gorn) 29-Oct-2000
  11. Revision History:
  12. --*/
  13. #include "clusrtlp.h"
  14. #include <wmistr.h>
  15. #include <evntrace.h>
  16. #define WppDebug(x,y)
  17. #define WPPINIT_STATIC
  18. #define WPP_REG_TRACE_REGKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Tracing"
  19. #define WPP_TEXTGUID_LEN 37
  20. static TRACEHANDLE WppQueryLogger(PCWSTR LoggerName)
  21. {
  22. ULONG status;
  23. EVENT_TRACE_PROPERTIES LoggerInfo;
  24. ZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
  25. LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
  26. LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  27. status = QueryTraceW(0, LoggerName, &LoggerInfo);
  28. WppDebug(4, ("QueryLogger(%ws) => %x:%x %d\n",
  29. LoggerName, LoggerInfo.Wnode.HistoricalContext, status) );
  30. if (status == ERROR_SUCCESS || status == ERROR_MORE_DATA) {
  31. return (TRACEHANDLE) LoggerInfo.Wnode.HistoricalContext;
  32. }
  33. return 0;
  34. }
  35. WPPINIT_STATIC
  36. __inline UINT WppHexVal(int ch) {
  37. return isdigit(ch) ? ch - '0' : ch - 'a' + 10;
  38. }
  39. WPPINIT_STATIC
  40. UINT WppHex(LPCWSTR s, int n)
  41. {
  42. UINT res = 0;
  43. while(n--) { res = res * 16 + WppHexVal(*s++); }
  44. return res;
  45. }
  46. WPPINIT_STATIC
  47. VOID
  48. WppGuidFromStr(
  49. IN LPCWSTR str,
  50. OUT LPGUID guid)
  51. {
  52. guid->Data1 = WppHex(str + 0, 8);
  53. guid->Data2 = (USHORT)WppHex(str + 9, 4);
  54. guid->Data3 = (USHORT)WppHex(str + 14, 4);
  55. guid->Data4[0] = (UCHAR) WppHex(str + 19, 2);
  56. guid->Data4[1] = (UCHAR) WppHex(str + 21, 2);
  57. guid->Data4[2] = (UCHAR) WppHex(str + 24, 2);
  58. guid->Data4[3] = (UCHAR) WppHex(str + 26, 2);
  59. guid->Data4[4] = (UCHAR) WppHex(str + 28, 2);
  60. guid->Data4[5] = (UCHAR) WppHex(str + 30, 2);
  61. guid->Data4[6] = (UCHAR) WppHex(str + 32, 2);
  62. guid->Data4[7] = (UCHAR) WppHex(str + 34, 2);
  63. }
  64. #define WPP_BUF_SIZE(hmem) ((hmem) ? (ULONG)LocalSize(hmem) : 0)
  65. // Make sure that the buffer is at least of size dwSize
  66. WPPINIT_STATIC
  67. DWORD WppGrowBuf(PVOID *Buf, DWORD dwSize)
  68. {
  69. DWORD status = ERROR_SUCCESS;
  70. WppDebug(4, ("WppGrowBuf(%x, %d (%d)) => ", *Buf, dwSize, WPP_BUF_SIZE(*Buf)) );
  71. if (*Buf == 0) {
  72. *Buf = LocalAlloc(LMEM_FIXED, dwSize);
  73. if (*Buf == 0) {
  74. status = GetLastError();
  75. }
  76. } else if (LocalSize(*Buf) < dwSize) {
  77. PVOID newBuf = LocalReAlloc(*Buf, dwSize, LMEM_MOVEABLE);
  78. if (newBuf) {
  79. *Buf = newBuf;
  80. } else {
  81. status = GetLastError();
  82. }
  83. }
  84. WppDebug(4, ("(%x (%d), %d)\n", *Buf, WPP_BUF_SIZE(*Buf), status) );
  85. return status;
  86. }
  87. WPPINIT_STATIC
  88. DWORD WppRegQueryGuid(
  89. IN HKEY hKey,
  90. IN LPCWSTR ValueName,
  91. OUT LPGUID pGuid
  92. )
  93. {
  94. WCHAR GuidTxt[WPP_TEXTGUID_LEN];
  95. DWORD status;
  96. DWORD dwLen = sizeof(GuidTxt);
  97. DWORD Type;
  98. status = RegQueryValueExW(
  99. hKey, // handle to key
  100. ValueName, // value name
  101. 0, // reserved
  102. &Type, // type buffer
  103. (LPBYTE)GuidTxt, // data buffer //
  104. &dwLen // size of data buffer
  105. );
  106. if (status != ERROR_SUCCESS || Type != REG_SZ || dwLen < 35) {
  107. return status;
  108. }
  109. WppGuidFromStr(GuidTxt, pGuid);
  110. return status;
  111. }
  112. WPPINIT_STATIC
  113. DWORD WppRegQueryDword(
  114. IN HKEY hKey,
  115. IN LPCWSTR ValueName,
  116. IN DWORD Default,
  117. IN DWORD MinVal,
  118. IN DWORD MaxVal
  119. )
  120. {
  121. DWORD Result = Default;
  122. DWORD dwLen = sizeof(DWORD);
  123. RegQueryValueExW(hKey, ValueName,
  124. 0, NULL, // lpReserved, lpType,
  125. (LPBYTE)&Result, &dwLen);
  126. if (Result < MinVal || Result > MaxVal) {
  127. Result = Default;
  128. }
  129. return Result;
  130. }
  131. WPPINIT_STATIC
  132. DWORD WppRegQueryString(
  133. IN HKEY hKey,
  134. IN LPCWSTR ValueName,
  135. IN OUT PWCHAR *Buf,
  136. IN DWORD ExtraPadding // Add this amount whenever we need to alloc more memory
  137. )
  138. {
  139. DWORD ExpandSize;
  140. DWORD BufSize;
  141. DWORD ValueSize = WPP_BUF_SIZE(*Buf);
  142. DWORD status;
  143. DWORD Type = 0;
  144. status = RegQueryValueExW(
  145. hKey, // handle to key
  146. ValueName, // value name
  147. 0, // reserved
  148. &Type, // type buffer
  149. (LPBYTE)(ValueSize?*Buf:ValueName), // data buffer //
  150. &ValueSize // size of data buffer
  151. );
  152. if (status == ERROR_MORE_DATA) {
  153. if (Type == REG_EXPAND_SZ) {
  154. ExtraPadding += ValueSize + 100; // Room for ExpandEnvStrings
  155. }
  156. status = WppGrowBuf(Buf, ValueSize + ExtraPadding);
  157. if (status != ERROR_SUCCESS) {
  158. return status;
  159. }
  160. status = RegQueryValueExW(
  161. hKey, // handle to key
  162. ValueName, // value name
  163. 0, // reserved
  164. &Type, // type buffer
  165. (LPBYTE)*Buf, // data buffer
  166. &ValueSize // size of data buffer
  167. );
  168. }
  169. if (status != ERROR_SUCCESS) {
  170. return status;
  171. }
  172. if (Type == REG_SZ) {
  173. return ERROR_SUCCESS;
  174. }
  175. if (Type != REG_EXPAND_SZ) {
  176. return ERROR_DATATYPE_MISMATCH;
  177. }
  178. if (wcschr(*Buf, '%') == 0) {
  179. // nothing to expand
  180. return ERROR_SUCCESS;
  181. }
  182. BufSize = (ULONG)LocalSize(*Buf);
  183. ExpandSize = sizeof(WCHAR) * ExpandEnvironmentStringsW(
  184. *Buf, (LPWSTR)((LPBYTE)*Buf + ValueSize), (BufSize - ValueSize) / sizeof(WCHAR) ) ;
  185. if (ExpandSize + ValueSize > BufSize) {
  186. status = WppGrowBuf(Buf, ExpandSize + max(ExpandSize, ValueSize) + ExtraPadding );
  187. if (status != ERROR_SUCCESS) {
  188. return status;
  189. }
  190. ExpandSize = ExpandEnvironmentStringsW(*Buf, (LPWSTR)((LPBYTE)*Buf + ValueSize), ExpandSize / sizeof(WCHAR));
  191. }
  192. if (ExpandSize == 0) {
  193. return GetLastError();
  194. }
  195. // Copy expanded string on top of the original one
  196. MoveMemory(*Buf, (LPBYTE)*Buf + ValueSize, ExpandSize);
  197. return ERROR_SUCCESS;
  198. }
  199. WPPINIT_STATIC
  200. void
  201. WppSetExt(LPWSTR buf, int i)
  202. {
  203. buf[0] = '.';
  204. buf[4] = 0;
  205. buf[3] = (WCHAR)('0' + i % 10); i = i / 10;
  206. buf[2] = (WCHAR)('0' + i % 10); i = i / 10;
  207. buf[1] = (WCHAR)('0' + i % 10);
  208. }
  209. #if !defined(WPP_DEFAULT_LOGGER_FLAGS)
  210. # define WPP_DEFAULT_LOGGER_FLAGS (EVENT_TRACE_FILE_MODE_CIRCULAR | EVENT_TRACE_USE_GLOBAL_SEQUENCE)
  211. #endif
  212. // A set of buffers used by an autostart
  213. // Buffers are reused between iterations and recursive invocations
  214. // to minimize number of allocations
  215. typedef struct _WPP_AUTO_START_BUFFERS {
  216. PWCHAR LogSessionName;
  217. PWCHAR Buf;
  218. } WPP_AUTO_START_BUFFERS, *PWPP_AUTO_START_BUFFERS;
  219. WPPINIT_STATIC
  220. DWORD
  221. WppReadLoggerInfo(
  222. IN HKEY LoggerKey,
  223. IN OUT PWPP_AUTO_START_BUFFERS x,
  224. OUT TRACEHANDLE* Logger)
  225. {
  226. DWORD status;
  227. PEVENT_TRACE_PROPERTIES Trace;
  228. DWORD len, sessionNameLen;
  229. DWORD MaxBackups = 0;
  230. DWORD ExtraPadding; // add this amount when we need to allocate
  231. status = WppRegQueryString(LoggerKey, L"LogSessionName", &x->LogSessionName, 0);
  232. if (status != ERROR_SUCCESS) {
  233. // this registry node doesn't contain a logger
  234. return status;
  235. }
  236. sessionNameLen = wcslen(x->LogSessionName);
  237. *Logger = WppQueryLogger(x->LogSessionName);
  238. if (*Logger) {
  239. WppDebug(1,("[WppInit] Logger %ls is already running\n", x->LogSessionName) );
  240. return ERROR_SUCCESS;
  241. }
  242. // The TraceProperties property buffer that we need to give to StartTrace
  243. // should be of size EVENT_TRACE_PROPERTIES + len(sessionName) + len(logFileName)
  244. // However, we don't know the length of logFileName at the moment. To eliminate
  245. // extra allocations we will add ExtraPadding to an any allocation, so that the final
  246. // buffer will be of required size
  247. ExtraPadding = sizeof(EVENT_TRACE_PROPERTIES) + (sessionNameLen + 1) * sizeof(WCHAR);
  248. status = WppRegQueryString(LoggerKey, L"LogFileName", &x->Buf, ExtraPadding);
  249. if (status != ERROR_SUCCESS) {
  250. WppDebug(1,("[WppInit] Read %ls\\LogFileName failed, %d\n", x->LogSessionName, status) );
  251. return status;
  252. }
  253. len = wcslen(x->Buf);
  254. MaxBackups = WppRegQueryDword(LoggerKey, L"MaxBackups", 0, 0, 999);
  255. if (MaxBackups) {
  256. int i, success;
  257. LPWSTR FromExt, ToExt, From, To;
  258. // Copy current.evm => current.evm.001, 001 => 002, etc
  259. // MakeSure, Buffer is big enought for two file names + .000 extensions
  260. WppGrowBuf(&x->Buf, (len + 5) * 2 * sizeof(WCHAR) + ExtraPadding); // .xxx\0 (5)
  261. From = x->Buf; // MyFileName.evm MyFileName.evm.001
  262. FromExt = From + len ; // ^ ^ ^ ^
  263. To = FromExt + 5; // .xxx0 // From Ext1 To Ext2
  264. ToExt = To + len;
  265. memcpy(To, From, (len + 1) * sizeof(WCHAR) );
  266. for (i = MaxBackups; i >= 1; --i) {
  267. WppSetExt(ToExt, i);
  268. if (i == 1) {
  269. *FromExt = 0; // remove extension
  270. } else {
  271. WppSetExt(FromExt, i-1);
  272. }
  273. success = MoveFileExW(From, To, MOVEFILE_REPLACE_EXISTING);
  274. if (!success) {
  275. status = GetLastError();
  276. } else {
  277. status = ERROR_SUCCESS;
  278. }
  279. WppDebug(3, ("[WppInit] Rename %ls => %ls, status %d\n",
  280. From, To, status) );
  281. }
  282. }
  283. status = WppGrowBuf(&x->Buf, ExtraPadding + (len + 1) * sizeof(WCHAR) );
  284. if (status != ERROR_SUCCESS) {
  285. return status;
  286. }
  287. MoveMemory((LPBYTE)x->Buf + sizeof(EVENT_TRACE_PROPERTIES), x->Buf, (len + 1) * sizeof(WCHAR) ); // Free room for the header
  288. Trace = (PEVENT_TRACE_PROPERTIES)x->Buf;
  289. ZeroMemory(Trace, sizeof(EVENT_TRACE_PROPERTIES) );
  290. Trace->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + (len + sessionNameLen + 2) * sizeof(WCHAR);
  291. Trace->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  292. Trace->BufferSize = WppRegQueryDword(LoggerKey, L"BufferSize", 0, 0, ~0u);
  293. Trace->MinimumBuffers = WppRegQueryDword(LoggerKey, L"MinimumBuffers", 0, 0, ~0u);
  294. Trace->MaximumBuffers = WppRegQueryDword(LoggerKey, L"MaximumBuffers", 0, 0, ~0u);
  295. Trace->MaximumFileSize = WppRegQueryDword(LoggerKey, L"MaximumFileSize", 0, 0, ~0u);
  296. Trace->LogFileMode = WppRegQueryDword(LoggerKey, L"LogFileMode", WPP_DEFAULT_LOGGER_FLAGS, 0, ~0u);
  297. Trace->FlushTimer = WppRegQueryDword(LoggerKey, L"FlushTimer", 0, 0, ~0u);
  298. Trace->EnableFlags = WppRegQueryDword(LoggerKey, L"EnableFlags", 0, 0, ~0u);
  299. Trace->AgeLimit = WppRegQueryDword(LoggerKey, L"AgeLimit", 0, 0, ~0u);
  300. Trace->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  301. Trace->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + (len + 1) * sizeof(WCHAR);
  302. wcscpy((LPWSTR)((LPBYTE)x->Buf + Trace->LoggerNameOffset), x->LogSessionName);
  303. status = StartTraceW(Logger, x->LogSessionName, Trace);
  304. WppDebug(1, ("[WppInit] Logger %ls started %x:%x %d\n", x->LogSessionName, *Logger, status) );
  305. return status;
  306. }
  307. typedef struct _WPP_INHERITED_DATA {
  308. TRACEHANDLE Logger;
  309. ULONG ControlFlags;
  310. ULONG ControlLevel;
  311. } WPP_INHERITED_DATA, *PWPP_INHERITED_DATA;
  312. WPPINIT_STATIC
  313. ULONG
  314. WppAutoStartInternal(
  315. IN HKEY Dir OPTIONAL, // if 0, use TracingKey ...
  316. IN LPCWSTR ProductName,
  317. IN PWPP_INHERITED_DATA InheritedData OPTIONAL,
  318. IN OUT PWPP_AUTO_START_BUFFERS x // to minimize data allocations, the buffers are reused
  319. )
  320. {
  321. ULONG status;
  322. WPP_INHERITED_DATA data;
  323. HKEY CloseMe = 0;
  324. HKEY hk = 0;
  325. DWORD dwSizeOfModuleName;
  326. DWORD dwIndex;
  327. GUID Guid;
  328. WppDebug(2, ("[WppInit] Init %ls\n", ProductName) );
  329. if (InheritedData) {
  330. data = *InheritedData;
  331. } else {
  332. ZeroMemory(&data, sizeof(data));
  333. }
  334. if (!Dir) {
  335. status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, WPP_REG_TRACE_REGKEY, 0, KEY_READ, &Dir);
  336. if (status != ERROR_SUCCESS) {
  337. WppDebug(1, ("[WppInit] Failed to open Trace Key, %d\n", status) );
  338. goto exit_gracefully;
  339. }
  340. CloseMe = Dir;
  341. if (WppRegQueryDword(Dir, L"NoAutoStart", 0, 0, 1) == 1) {
  342. WppDebug(1, ("[WppInit] Auto-start vetoed\n") );
  343. goto exit_gracefully;
  344. }
  345. }
  346. status = RegOpenKeyExW(Dir, ProductName, 0, KEY_READ, &hk);
  347. if (status != ERROR_SUCCESS) {
  348. WppDebug(1, ("[WppInit] Failed to open %ls subkey, %d\n", ProductName, status) );
  349. goto exit_gracefully;
  350. }
  351. if (WppRegQueryDword(Dir, L"Active", 1, 0, 1) == 0) {
  352. WppDebug(1, ("[WppInit] Tracing is not active for %ls\n", ProductName) );
  353. goto exit_gracefully;
  354. }
  355. WppReadLoggerInfo(hk, x, &data.Logger);
  356. data.ControlLevel = WppRegQueryDword(hk, L"ControlLevel", data.ControlLevel, 0, ~0u);
  357. data.ControlFlags = WppRegQueryDword(hk, L"ControlFlags", data.ControlFlags, 0, ~0u);
  358. if (WppRegQueryGuid(hk, L"Guid", &Guid) == ERROR_SUCCESS) {
  359. // We can try to start tracing //
  360. if (data.Logger) {
  361. status = EnableTrace(1, data.ControlFlags, data.ControlLevel,
  362. &Guid, data.Logger);
  363. WppDebug(1, ("[WppInit] Enable %ls, status %d\n", ProductName, status) );
  364. }
  365. }
  366. dwSizeOfModuleName = WPP_BUF_SIZE(x->Buf);
  367. dwIndex = 0;
  368. while (ERROR_SUCCESS == (status = RegEnumKeyExW(hk, dwIndex,
  369. x->Buf, &dwSizeOfModuleName,
  370. NULL, NULL, NULL, NULL)))
  371. {
  372. status = WppAutoStartInternal(hk, x->Buf, &data, x);
  373. dwSizeOfModuleName = WPP_BUF_SIZE(x->Buf);
  374. ++dwIndex;
  375. }
  376. if (ERROR_NO_MORE_ITEMS == status) {
  377. status = ERROR_SUCCESS;
  378. }
  379. exit_gracefully:
  380. if (CloseMe) {
  381. RegCloseKey(CloseMe);
  382. }
  383. if (hk) {
  384. RegCloseKey(hk);
  385. }
  386. return status;
  387. }
  388. ULONG
  389. WppAutoStart(
  390. IN LPCWSTR ProductName
  391. )
  392. {
  393. WPP_AUTO_START_BUFFERS x;
  394. ULONG status;
  395. x.LogSessionName = 0;
  396. x.Buf = 0;
  397. if (ProductName == NULL) {
  398. return ERROR_SUCCESS;
  399. }
  400. if( WppGrowBuf(&x.Buf, 1024) == ERROR_SUCCESS &&
  401. WppGrowBuf(&x.LogSessionName, 64) == ERROR_SUCCESS )
  402. {
  403. WppDebug(1, ("[WppInit] Initialize %ls\n", ProductName) );
  404. status = WppAutoStartInternal(0, ProductName, 0, &x);
  405. } else {
  406. WppDebug(1, ("[WppInit] Allocation failure\n") );
  407. status = ERROR_OUTOFMEMORY;
  408. }
  409. LocalFree(x.Buf);
  410. LocalFree(x.LogSessionName);
  411. return status;
  412. }