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.

660 lines
19 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. log.cpp
  5. Abstract:
  6. This file implements the BITS server extensions logging
  7. --*/
  8. #include "precomp.h"
  9. #include "sddl.h"
  10. #define ARRAYSIZE(x) (sizeof((x))/sizeof((x)[0]))
  11. const DWORD g_LogLineSize = 160;
  12. typedef char LOG_LINE_TYPE[g_LogLineSize];
  13. CRITICAL_SECTION g_LogCs;
  14. bool g_LogFileEnabled = false;
  15. #ifdef DEBUG
  16. bool g_LogDebuggerEnabled = true;
  17. #else
  18. bool g_LogDebuggerEnabled = false;
  19. #endif
  20. bool g_fPerProcessLog = false;
  21. UINT32 g_LogFlags = DEFAULT_LOG_FLAGS;
  22. HANDLE g_LogFile = INVALID_HANDLE_VALUE;
  23. HANDLE g_LogFileMapping = NULL;
  24. const DWORD LOG_FILENAME_LEN = MAX_PATH*2;
  25. char g_LogDefaultFileName[ LOG_FILENAME_LEN ];
  26. char g_LogRegistryFileName[ LOG_FILENAME_LEN ];
  27. char *g_LogFileName = NULL;
  28. char g_LogBuffer[512];
  29. UINT64 g_LogSlots = (DEFAULT_LOG_SIZE * 1000000 ) / g_LogLineSize;
  30. DWORD g_LogSequence = 0;
  31. UINT64 g_LogCurrentSlot = 1;
  32. LOG_LINE_TYPE *g_LogFileBase = NULL;
  33. // Allow access to local system, administrators, creator/owner
  34. const char g_LogBaseSecurityString[] = "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;CO)";
  35. const char g_LogPartialSecurityString[] = "(A;;GA;;;";
  36. LPSTR
  37. GetCurrentThreadSidString()
  38. {
  39. HANDLE hToken = NULL;
  40. LPBYTE pTokenUser = NULL;
  41. DWORD dwReqSize = 0;
  42. PSID pUserSid = NULL;
  43. DWORD dwError = ERROR_SUCCESS;
  44. LPSTR pszSidString = NULL;
  45. try
  46. {
  47. //
  48. // Open the thread token.
  49. //
  50. if ( !OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken) )
  51. {
  52. dwError = GetLastError();
  53. if ( dwError == ERROR_NO_TOKEN )
  54. {
  55. //
  56. // This thread is not impersonated and has no SID.
  57. // Try to open process token instead
  58. //
  59. if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) )
  60. {
  61. dwError = GetLastError();
  62. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  63. }
  64. }
  65. else
  66. {
  67. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  68. }
  69. }
  70. //
  71. // Get the user's SID.
  72. //
  73. if ( !GetTokenInformation(hToken,
  74. TokenUser,
  75. NULL,
  76. 0,
  77. &dwReqSize) )
  78. {
  79. dwError = GetLastError();
  80. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  81. {
  82. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  83. }
  84. dwError = ERROR_SUCCESS;
  85. }
  86. pTokenUser = new BYTE[ dwReqSize ];
  87. if ( !GetTokenInformation(hToken,
  88. TokenUser,
  89. (LPVOID)pTokenUser,
  90. dwReqSize,
  91. &dwReqSize) )
  92. {
  93. dwError = GetLastError();
  94. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  95. }
  96. if (pTokenUser)
  97. {
  98. pUserSid = (reinterpret_cast<TOKEN_USER *>(pTokenUser))->User.Sid;
  99. }
  100. if ( !IsValidSid(pUserSid) )
  101. {
  102. throw ComError( HRESULT_FROM_WIN32( ERROR_INVALID_SID ) );
  103. }
  104. if ( !ConvertSidToStringSid(pUserSid, &pszSidString) )
  105. {
  106. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  107. }
  108. }
  109. catch ( ComError Error )
  110. {
  111. if ( hToken )
  112. {
  113. CloseHandle(hToken);
  114. hToken = NULL;
  115. }
  116. if ( pTokenUser )
  117. {
  118. delete [] pTokenUser;
  119. pTokenUser = NULL;
  120. }
  121. throw;
  122. }
  123. if ( hToken )
  124. {
  125. CloseHandle(hToken);
  126. hToken = NULL;
  127. }
  128. if ( pTokenUser )
  129. {
  130. delete [] pTokenUser;
  131. pTokenUser = NULL;
  132. }
  133. //
  134. // caller has to free this memory by calling
  135. // LocalFree(static_cast<HLOCAL>(pszSidString));
  136. //
  137. return pszSidString;
  138. }
  139. LPSTR
  140. AddAclForCurrentUser(LPCSTR szBaseAcl, LPCSTR szUserPartialAclPrefix)
  141. {
  142. LPCSTR szUserPartialAclSuffix = ")";
  143. LPSTR szFullAcl = NULL;
  144. DWORD cchFullAcl = 0;
  145. LPSTR pszUserSID = NULL;
  146. try
  147. {
  148. pszUserSID = GetCurrentThreadSidString();
  149. cchFullAcl = strlen(szBaseAcl) + strlen(szUserPartialAclPrefix) + strlen(pszUserSID) + strlen(szUserPartialAclSuffix) + 1;
  150. // ATT: this buffer is being allocated and it should be freed by the caller
  151. szFullAcl = new CHAR[ cchFullAcl ];
  152. StringCchPrintf(szFullAcl, cchFullAcl, "%s%s%s%s", szBaseAcl, szUserPartialAclPrefix, pszUserSID, szUserPartialAclSuffix);
  153. }
  154. catch( ComError Error )
  155. {
  156. //
  157. // Free the String SID obtained by calling ConvertSidToStringSid()
  158. //
  159. if (pszUserSID)
  160. {
  161. LocalFree(reinterpret_cast<HLOCAL>(pszUserSID));
  162. pszUserSID = NULL;
  163. }
  164. throw;
  165. }
  166. //
  167. // Free the String SID obtained by calling ConvertSidToStringSid()
  168. //
  169. if (pszUserSID)
  170. {
  171. LocalFree(reinterpret_cast<HLOCAL>(pszUserSID));
  172. pszUserSID = NULL;
  173. }
  174. //
  175. // this string should be freed by the caller
  176. // by calling delete [] szFullAcl
  177. //
  178. return szFullAcl;
  179. }
  180. void OpenLogFile()
  181. {
  182. bool NewFile = false;
  183. LPSTR szSDDLString = NULL;
  184. {
  185. SECURITY_ATTRIBUTES SecurityAttributes;
  186. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  187. try
  188. {
  189. //
  190. // We get into the trouble of adding the thread's impersonation sid because on IIS6
  191. // the w3wp.exe process can run with arbitrary identities. The default is to launch
  192. // the process using the Network Services account.
  193. //
  194. // So we will be granting log file access to Administrators, Local System and whom
  195. // ever is impersonating the host process when the isapi is loaded. Note that
  196. // if the account used for these process is changed after the file is first created,
  197. // the isapi might lose the right to open the log, if the new user is not part of
  198. // the administrator's group.
  199. //
  200. szSDDLString = AddAclForCurrentUser(g_LogBaseSecurityString, g_LogPartialSecurityString);
  201. }
  202. catch ( ComError Error )
  203. {
  204. // bail out -- we will have no logging
  205. return;
  206. }
  207. if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
  208. szSDDLString,
  209. SDDL_REVISION_1,
  210. &pSecurityDescriptor,
  211. NULL ) )
  212. return;
  213. SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
  214. SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  215. SecurityAttributes.bInheritHandle = FALSE;
  216. g_LogFile =
  217. CreateFile(
  218. g_LogFileName,
  219. GENERIC_READ | GENERIC_WRITE,
  220. FILE_SHARE_READ | FILE_SHARE_WRITE,
  221. &SecurityAttributes,
  222. OPEN_ALWAYS,
  223. FILE_ATTRIBUTE_NORMAL,
  224. NULL );
  225. LocalFree( (HLOCAL)pSecurityDescriptor );
  226. if ( INVALID_HANDLE_VALUE == g_LogFile )
  227. return;
  228. }
  229. SetFilePointer( g_LogFile, 0, NULL, FILE_BEGIN );
  230. LOG_LINE_TYPE FirstLine;
  231. DWORD dwBytesRead = 0;
  232. if (!ReadFile( g_LogFile,
  233. FirstLine,
  234. g_LogLineSize,
  235. &dwBytesRead,
  236. NULL ) )
  237. goto fatalerror;
  238. DWORD LineSize;
  239. UINT64 LogSlots;
  240. if ( dwBytesRead != g_LogLineSize ||
  241. 4 != sscanf( FirstLine, "# %u %I64u %u %I64u", &LineSize, &LogSlots, &g_LogSequence, &g_LogCurrentSlot ) ||
  242. LineSize != g_LogLineSize ||
  243. LogSlots != g_LogSlots )
  244. {
  245. NewFile = true;
  246. g_LogSequence = 0;
  247. g_LogCurrentSlot = 1;
  248. if ( INVALID_SET_FILE_POINTER == SetFilePointer( g_LogFile, (DWORD)g_LogSlots * g_LogLineSize, NULL, FILE_BEGIN ) )
  249. goto fatalerror;
  250. if ( !SetEndOfFile( g_LogFile ) )
  251. goto fatalerror;
  252. SetFilePointer( g_LogFile, 0, NULL, FILE_BEGIN );
  253. }
  254. g_LogFileMapping =
  255. CreateFileMapping(
  256. g_LogFile,
  257. NULL,
  258. PAGE_READWRITE,
  259. 0,
  260. 0,
  261. NULL );
  262. if ( !g_LogFileMapping )
  263. goto fatalerror;
  264. g_LogFileBase = (LOG_LINE_TYPE *)
  265. MapViewOfFile(
  266. g_LogFileMapping, // handle to file-mapping object
  267. FILE_MAP_WRITE | FILE_MAP_READ,// access mode
  268. 0, // high-order DWORD of offset
  269. 0, // low-order DWORD of offset
  270. 0 // number of bytes to map
  271. );
  272. if ( !g_LogFileBase )
  273. goto fatalerror;
  274. if ( NewFile )
  275. {
  276. LOG_LINE_TYPE FillTemplate;
  277. memset( FillTemplate, ' ', sizeof( FillTemplate ) );
  278. StringCchPrintfA(
  279. FillTemplate,
  280. g_LogLineSize,
  281. "# %u %I64u %u %I64u",
  282. g_LogLineSize,
  283. g_LogSlots,
  284. g_LogSequence,
  285. g_LogCurrentSlot );
  286. FillTemplate[ g_LogLineSize - 2 ] = '\r';
  287. FillTemplate[ g_LogLineSize - 1 ] = '\n';
  288. memcpy( g_LogFileBase, FillTemplate, sizeof( FillTemplate ) );
  289. memset( FillTemplate, '9', sizeof( FillTemplate ) );
  290. FillTemplate[ g_LogLineSize - 2 ] = '\r';
  291. FillTemplate[ g_LogLineSize - 1 ] = '\n';
  292. for( SIZE_T i=1; i < g_LogSlots; i++ )
  293. memcpy( g_LogFileBase + i, FillTemplate, sizeof( FillTemplate ) );
  294. }
  295. g_LogFileEnabled = true;
  296. return;
  297. fatalerror:
  298. if ( g_LogFileBase )
  299. {
  300. UnmapViewOfFile( (LPCVOID)g_LogFileBase );
  301. g_LogFileBase = NULL;
  302. }
  303. if ( g_LogFileMapping )
  304. {
  305. CloseHandle( g_LogFileMapping );
  306. g_LogFileMapping = NULL;
  307. }
  308. if ( INVALID_HANDLE_VALUE != g_LogFile )
  309. {
  310. CloseHandle( g_LogFile );
  311. g_LogFile = INVALID_HANDLE_VALUE;
  312. }
  313. }
  314. HRESULT LogInit()
  315. {
  316. if ( !InitializeCriticalSectionAndSpinCount( &g_LogCs, 0x80000000 ) )
  317. return HRESULT_FROM_WIN32( GetLastError() );
  318. if (!GetSystemDirectory( g_LogDefaultFileName, LOG_FILENAME_LEN ) )
  319. {
  320. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  321. DeleteCriticalSection( &g_LogCs );
  322. return Hr;
  323. }
  324. StringCchCatA(
  325. g_LogDefaultFileName,
  326. LOG_FILENAME_LEN,
  327. "\\bitsserver.log" );
  328. g_LogFileName = g_LogDefaultFileName;
  329. HKEY Key = NULL;
  330. if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, LOG_SETTINGS_PATH, &Key ) )
  331. {
  332. DWORD Type;
  333. DWORD DataSize = sizeof( g_LogRegistryFileName );
  334. if ( ERROR_SUCCESS == RegQueryValueEx( Key,
  335. LOG_FILENAME_VALUE,
  336. NULL,
  337. &Type,
  338. (LPBYTE)g_LogRegistryFileName,
  339. &DataSize ) &&
  340. ( ( REG_EXPAND_SZ == Type ) || ( REG_SZ == Type ) ) )
  341. {
  342. g_LogFileName = g_LogRegistryFileName;
  343. }
  344. DWORD LogRegistryFlags;
  345. DataSize = sizeof( LogRegistryFlags );
  346. if ( ERROR_SUCCESS == RegQueryValueEx( Key,
  347. LOG_FLAGS_VALUE,
  348. NULL,
  349. &Type,
  350. (LPBYTE)&LogRegistryFlags,
  351. &DataSize ) &&
  352. ( REG_DWORD == Type ) )
  353. {
  354. g_LogFlags = LogRegistryFlags;
  355. }
  356. DWORD LogSize;
  357. DataSize = sizeof( LogSize );
  358. if ( ERROR_SUCCESS == RegQueryValueEx( Key,
  359. LOG_SIZE_VALUE,
  360. NULL,
  361. &Type,
  362. (LPBYTE)&LogSize,
  363. &DataSize ) &&
  364. ( REG_DWORD == Type ) )
  365. {
  366. g_LogSlots = ( LogSize * 1000000 ) / g_LogLineSize;
  367. }
  368. DWORD fRegistryPerProcessLog;
  369. DataSize = sizeof( fRegistryPerProcessLog );
  370. if ( ERROR_SUCCESS == RegQueryValueEx( Key,
  371. PER_PROCESS_LOG_VALUE,
  372. NULL,
  373. &Type,
  374. (LPBYTE)&fRegistryPerProcessLog,
  375. &DataSize ) &&
  376. ( REG_DWORD == Type ) )
  377. {
  378. g_fPerProcessLog = ((fRegistryPerProcessLog == 0)? false : true);
  379. }
  380. RegCloseKey( Key );
  381. Key = NULL;
  382. }
  383. //
  384. // Override the filename key and set the logfilename to be <logfilename>_pid<processid>.log
  385. // this feature is important for the case where we have more than one application pool
  386. // or webgardens is enabled.
  387. //
  388. // We won't be looking for failures of the StringCch* functions here. The buffer used
  389. // is very large for path names (2*MAX_PATH), and there's not a lot we can do to
  390. // handle the error cases. THe functions are guaranteed to be safe -- no buffer overruns.
  391. // The worst that can happen is the filename extension to be truncated.
  392. //
  393. if ( g_fPerProcessLog )
  394. {
  395. CHAR szExt[_MAX_EXT];
  396. CHAR *pExt = NULL;
  397. CHAR szPid[30];
  398. pExt = PathFindExtension(g_LogFileName);
  399. // if the file doesn't have an extension, pExt will point to the trainling '\0',
  400. // and this is fine
  401. StringCchCopyA(szExt, ARRAYSIZE(szExt), pExt);
  402. // get rid of the extension so we can append the process id
  403. *pExt = '\0';
  404. // Add the processId
  405. StringCchPrintf(szPid, ARRAYSIZE(szPid), "%u", GetCurrentProcessId());
  406. StringCchCatA(g_LogFileName, LOG_FILENAME_LEN, "_pid");
  407. StringCchCatA(g_LogFileName, LOG_FILENAME_LEN, szPid);
  408. // add the extension back to the filename
  409. StringCchCatA(g_LogFileName, LOG_FILENAME_LEN, szExt);
  410. }
  411. if ( g_LogFlags && g_LogFileName && g_LogSlots )
  412. {
  413. OpenLogFile();
  414. }
  415. Log( LOG_INFO, "Starting log session");
  416. return S_OK;
  417. }
  418. void LogClose()
  419. {
  420. EnterCriticalSection( &g_LogCs );
  421. Log( LOG_INFO, "Closing log session");
  422. if ( g_LogFileBase )
  423. {
  424. memset( g_LogFileBase[0], ' ', sizeof( g_LogLineSize ) );
  425. StringCchPrintfA(
  426. g_LogFileBase[0],
  427. g_LogLineSize,
  428. "# %u %I64u %u %I64u",
  429. g_LogLineSize,
  430. g_LogSlots,
  431. g_LogSequence,
  432. g_LogCurrentSlot );
  433. g_LogFileBase[0][ g_LogLineSize - 2 ] = '\r';
  434. g_LogFileBase[0][ g_LogLineSize - 1 ] = '\n';
  435. UnmapViewOfFile( (LPCVOID)g_LogFileBase );
  436. g_LogFileBase = NULL;
  437. }
  438. if ( g_LogFileMapping )
  439. {
  440. CloseHandle( g_LogFileMapping );
  441. g_LogFileMapping = NULL;
  442. }
  443. if ( INVALID_HANDLE_VALUE != g_LogFile )
  444. {
  445. CloseHandle( g_LogFile );
  446. g_LogFile = INVALID_HANDLE_VALUE;
  447. }
  448. DeleteCriticalSection( &g_LogCs );
  449. }
  450. void LogInternal( UINT32 LogFlags, char *Format, va_list arglist )
  451. {
  452. if ( !g_LogFileEnabled && !g_LogDebuggerEnabled )
  453. return;
  454. DWORD LastError = GetLastError();
  455. EnterCriticalSection( &g_LogCs );
  456. DWORD ThreadId = GetCurrentThreadId();
  457. DWORD ProcessId = GetCurrentProcessId();
  458. SYSTEMTIME Time;
  459. GetLocalTime( &Time );
  460. StringCchVPrintfA(
  461. g_LogBuffer,
  462. sizeof(g_LogBuffer) - 1,
  463. Format, arglist );
  464. int CharsWritten = strlen( g_LogBuffer );
  465. char *BeginPointer = g_LogBuffer;
  466. char *EndPointer = g_LogBuffer + CharsWritten;
  467. DWORD MinorSequence = 0;
  468. while ( BeginPointer < EndPointer )
  469. {
  470. static char StaticLineBuffer[ g_LogLineSize ];
  471. char *LineBuffer = StaticLineBuffer;
  472. if ( g_LogFileBase )
  473. {
  474. LineBuffer = g_LogFileBase[ g_LogCurrentSlot ];
  475. g_LogCurrentSlot = ( g_LogCurrentSlot + 1 ) % g_LogSlots;
  476. // leave the first line alone
  477. if ( !g_LogCurrentSlot )
  478. g_LogCurrentSlot = ( g_LogCurrentSlot + 1 ) % g_LogSlots;
  479. }
  480. char *CurrentOutput = LineBuffer;
  481. StringCchPrintfA(
  482. LineBuffer,
  483. g_LogLineSize,
  484. "%.8X.%.2X %.2u/%.2u/%.4u-%.2u:%.2u:%.2u.%.3u %.4X.%.4X %s|%s|%s|%s|%s ",
  485. g_LogSequence,
  486. MinorSequence++,
  487. Time.wMonth,
  488. Time.wDay,
  489. Time.wYear,
  490. Time.wHour,
  491. Time.wMinute,
  492. Time.wSecond,
  493. Time.wMilliseconds,
  494. ProcessId,
  495. ThreadId,
  496. ( LogFlags & LOG_INFO ) ? "I" : "-",
  497. ( LogFlags & LOG_WARNING ) ? "W" : "-",
  498. ( LogFlags & LOG_ERROR ) ? "E" : "-",
  499. ( LogFlags & LOG_CALLBEGIN ) ? "CB" : "--",
  500. ( LogFlags & LOG_CALLEND ) ? "CE" : "--" );
  501. int HeaderSize = strlen( LineBuffer );
  502. int SpaceAvailable = g_LogLineSize - HeaderSize - 2; // 2 bytes for /r/n
  503. int OutputChars = min( (int)( EndPointer - BeginPointer ), SpaceAvailable );
  504. int PadChars = SpaceAvailable - OutputChars;
  505. CurrentOutput += HeaderSize;
  506. memcpy( CurrentOutput, BeginPointer, OutputChars );
  507. CurrentOutput += OutputChars;
  508. BeginPointer += OutputChars;
  509. memset( CurrentOutput, ' ', PadChars );
  510. CurrentOutput += PadChars;
  511. *CurrentOutput++ = '\r';
  512. *CurrentOutput++ = '\n';
  513. ASSERT( CurrentOutput - LineBuffer == g_LogLineSize );
  514. if ( g_LogDebuggerEnabled )
  515. {
  516. static char DebugLineBuffer[ g_LogLineSize + 1];
  517. memcpy( DebugLineBuffer, LineBuffer, g_LogLineSize );
  518. DebugLineBuffer[ g_LogLineSize ] = '\0';
  519. OutputDebugString( DebugLineBuffer );
  520. }
  521. }
  522. g_LogSequence++;
  523. LeaveCriticalSection( &g_LogCs );
  524. SetLastError( LastError );
  525. }