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.

654 lines
14 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. WBEMUTIL.CPP
  5. Abstract:
  6. General utility functions.
  7. History:
  8. a-raymcc 17-Apr-96 Created.
  9. --*/
  10. #include "precomp.h"
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <time.h>
  14. #include <stdio.h>
  15. #include <wbemutil.h>
  16. #include <corex.h>
  17. #include "reg.h"
  18. #include <TCHAR.H>
  19. #include "sync.h"
  20. #include <ARRTEMPL.H>
  21. class AutoRevert
  22. {
  23. private:
  24. HANDLE oldToken_;
  25. bool self_;
  26. public:
  27. AutoRevert();
  28. ~AutoRevert();
  29. void dismiss();
  30. bool self(){ return self_;}
  31. };
  32. AutoRevert::AutoRevert():oldToken_(NULL),self_(true)
  33. {
  34. if (OpenThreadToken(GetCurrentThread(),TOKEN_IMPERSONATE,TRUE,&oldToken_))
  35. {
  36. RevertToSelf();
  37. }else
  38. {
  39. if (GetLastError() != ERROR_NO_TOKEN)
  40. self_ = false;
  41. };
  42. }
  43. AutoRevert::~AutoRevert()
  44. {
  45. dismiss();
  46. }
  47. void AutoRevert::dismiss()
  48. {
  49. if (oldToken_)
  50. {
  51. SetThreadToken(NULL,oldToken_);
  52. CloseHandle(oldToken_);
  53. }
  54. }
  55. //***************************************************************************
  56. //
  57. // BOOL isunialpha(wchar_t c)
  58. //
  59. // Used to test if a wide character is a unicode character or underscore.
  60. //
  61. // Parameters:
  62. // c = The character being tested.
  63. // Return value:
  64. // TRUE if OK.
  65. //
  66. //***************************************************************************
  67. BOOL POLARITY isunialpha(wchar_t c)
  68. {
  69. if(c == 0x5f || (0x41 <= c && c <= 0x5a) ||
  70. (0x61 <= c && c <= 0x7a) || (0x80 <= c && c <= 0xfffd))
  71. return TRUE;
  72. else
  73. return FALSE;
  74. }
  75. //***************************************************************************
  76. //
  77. // BOOL isunialphanum(char_t c)
  78. //
  79. // Used to test if a wide character is string suitable for identifiers.
  80. //
  81. // Parameters:
  82. // pwc = The character being tested.
  83. // Return value:
  84. // TRUE if OK.
  85. //
  86. //***************************************************************************
  87. BOOL POLARITY isunialphanum(wchar_t c)
  88. {
  89. if(isunialpha(c))
  90. return TRUE;
  91. else
  92. return iswdigit(c);
  93. }
  94. BOOL IsValidElementName( LPCWSTR wszName )
  95. {
  96. if(wszName[0] == 0)
  97. return FALSE;
  98. if(wszName[0] == '_')
  99. return FALSE;
  100. const WCHAR* pwc = wszName;
  101. // Check the first letter
  102. // ======================
  103. // this is for compatibility with IWbemPathParser
  104. if (iswspace(pwc[0]))
  105. return FALSE;
  106. if(!isunialpha(*pwc))
  107. return FALSE;
  108. pwc++;
  109. // Check the rest
  110. // ==============
  111. while(*pwc)
  112. {
  113. if(!isunialphanum(*pwc))
  114. return FALSE;
  115. pwc++;
  116. }
  117. if (iswspace(*(pwc-1)))
  118. return FALSE;
  119. if(pwc[-1] == '_')
  120. return FALSE;
  121. return TRUE;
  122. }
  123. // Can't use overloading and/or default parameters because
  124. // "C" files use these guys. No, I'm not happy about
  125. // this!
  126. BOOL IsValidElementName2( LPCWSTR wszName, BOOL bAllowUnderscore )
  127. {
  128. if(wszName[0] == 0)
  129. return FALSE;
  130. if(!bAllowUnderscore && wszName[0] == '_')
  131. return FALSE;
  132. const WCHAR* pwc = wszName;
  133. // Check the first letter
  134. // ======================
  135. // this is for compatibility with IWbemPathParser
  136. if (iswspace(pwc[0]))
  137. return FALSE;
  138. if(!isunialpha(*pwc))
  139. return FALSE;
  140. pwc++;
  141. // Check the rest
  142. // ==============
  143. while(*pwc)
  144. {
  145. if(!isunialphanum(*pwc))
  146. return FALSE;
  147. pwc++;
  148. }
  149. if (iswspace(*(pwc-1)))
  150. return FALSE;
  151. if(!bAllowUnderscore && pwc[-1] == '_')
  152. return FALSE;
  153. return TRUE;
  154. }
  155. BLOB POLARITY BlobCopy(BLOB *pSrc)
  156. {
  157. BLOB Blob;
  158. BYTE *p = new BYTE[pSrc->cbSize];
  159. // Check for allocation failure
  160. if ( NULL == p )
  161. {
  162. throw CX_MemoryException();
  163. }
  164. Blob.cbSize = pSrc->cbSize;
  165. Blob.pBlobData = p;
  166. memcpy(p, pSrc->pBlobData, Blob.cbSize);
  167. return Blob;
  168. }
  169. void POLARITY BlobAssign(BLOB *pBlob, LPVOID pBytes, DWORD dwCount, BOOL bAcquire)
  170. {
  171. BYTE *pSrc = 0;
  172. if (bAcquire)
  173. pSrc = (BYTE *) pBytes;
  174. else {
  175. pSrc = new BYTE[dwCount];
  176. // Check for allocation failure
  177. if ( NULL == pSrc )
  178. {
  179. throw CX_MemoryException();
  180. }
  181. memcpy(pSrc, pBytes, dwCount);
  182. }
  183. pBlob->cbSize = dwCount;
  184. pBlob->pBlobData = pSrc;
  185. }
  186. void POLARITY BlobClear(BLOB *pSrc)
  187. {
  188. if (pSrc->pBlobData)
  189. delete pSrc->pBlobData;
  190. pSrc->pBlobData = 0;
  191. pSrc->cbSize = 0;
  192. }
  193. class __Trace
  194. {
  195. struct ARMutex
  196. {
  197. HANDLE h_;
  198. ARMutex(HANDLE h):h_(h){}
  199. ~ARMutex(){ ReleaseMutex(h_);}
  200. };
  201. public:
  202. enum { REG_CHECK_INTERVAL =1000 * 60 };
  203. DWORD m_dwLogging;
  204. DWORD m_dwMaxLogSize;
  205. DWORD m_dwTimeLastRegCheck;
  206. wchar_t m_szLoggingDirectory[MAX_PATH+1];
  207. char m_szTraceBuffer[2048];
  208. char m_szTraceBuffer2[4096];
  209. wchar_t m_szBackupFileName[MAX_PATH+1];
  210. wchar_t m_szLogFileName[MAX_PATH+1];
  211. static const wchar_t *m_szLogFileNames[];
  212. BOOL LoggingLevelEnabled(DWORD dwLevel);
  213. int Trace(char caller, const char *fmt, va_list &argptr);
  214. __Trace();
  215. ~__Trace();
  216. HANDLE get_logfile(const wchar_t * name );
  217. private:
  218. void ReadLogDirectory();
  219. void ReReadRegistry();
  220. HANDLE buffers_lock_;
  221. };
  222. const wchar_t * __Trace::m_szLogFileNames[] =
  223. { FILENAME_PREFIX_CORE __TEXT(".log"),
  224. FILENAME_PREFIX_EXE __TEXT(".log"),
  225. FILENAME_PREFIX_ESS __TEXT(".log"),
  226. FILENAME_PREFIX_CLI_MARSH __TEXT(".log"),
  227. FILENAME_PREFIX_SERV_MARSH __TEXT(".log"),
  228. FILENAME_PREFIX_QUERY __TEXT(".log"),
  229. FILENAME_PROFIX_MOFCOMP __TEXT(".log"),
  230. FILENAME_PROFIX_EVENTLOG __TEXT(".log"),
  231. FILENAME_PROFIX_WBEMDISP __TEXT(".log"),
  232. FILENAME_PROFIX_STDPROV __TEXT(".log"),
  233. FILENAME_PROFIX_WMIPROV __TEXT(".log"),
  234. FILENAME_PROFIX_WMIOLEDB __TEXT(".log"),
  235. FILENAME_PREFIX_WMIADAP __TEXT(".log"),
  236. FILENAME_PREFIX_REPDRV __TEXT(".log")
  237. };
  238. __Trace __g_traceInfo;
  239. __Trace::__Trace()
  240. : m_dwLogging(1),
  241. m_dwMaxLogSize(65536),
  242. m_dwTimeLastRegCheck(GetTickCount())
  243. {
  244. buffers_lock_ = CreateMutex(0,0,0);
  245. ReadLogDirectory();
  246. ReReadRegistry();
  247. }
  248. __Trace::~__Trace()
  249. {
  250. CloseHandle(buffers_lock_);
  251. };
  252. void __Trace::ReReadRegistry()
  253. {
  254. Registry r(WBEM_REG_WINMGMT);
  255. //Get the logging level
  256. if (r.GetDWORDStr(__TEXT("Logging"), &m_dwLogging) != Registry::no_error)
  257. {
  258. m_dwLogging = 1;
  259. r.SetDWORDStr(__TEXT("Logging"), m_dwLogging);
  260. }
  261. //Get the maximum log file size
  262. if (r.GetDWORDStr(__TEXT("Log File Max Size"), &m_dwMaxLogSize) != Registry::no_error)
  263. {
  264. m_dwMaxLogSize = 65536;
  265. r.SetDWORDStr(__TEXT("Log File Max Size"), m_dwMaxLogSize);
  266. }
  267. }
  268. void __Trace::ReadLogDirectory()
  269. {
  270. Registry r(WBEM_REG_WINMGMT);
  271. //Retrieve the logging directory
  272. TCHAR *tmpStr = 0;
  273. if ((r.GetStr(__TEXT("Logging Directory"), &tmpStr) == Registry::failed) ||
  274. (lstrlen(tmpStr) > (MAX_PATH)))
  275. {
  276. delete [] tmpStr; //Just in case someone was trying for a buffer overrun with a long path in the registry...
  277. if (GetSystemDirectory(m_szLoggingDirectory, MAX_PATH+1) == 0)
  278. {
  279. lstrcpy(m_szLoggingDirectory, __TEXT("c:\\"));
  280. }
  281. else
  282. {
  283. lstrcat(m_szLoggingDirectory, __TEXT("\\WBEM\\Logs\\"));
  284. r.SetStr(__TEXT("Logging Directory"), m_szLoggingDirectory);
  285. }
  286. }
  287. else
  288. {
  289. lstrcpy(m_szLoggingDirectory, tmpStr);
  290. //make sure there is a '\' on the end of the path...
  291. if (m_szLoggingDirectory[lstrlen(m_szLoggingDirectory) - 1] != '\\')
  292. {
  293. lstrcat(m_szLoggingDirectory, __TEXT("\\"));
  294. r.SetStr(__TEXT("Logging Directory"), m_szLoggingDirectory);
  295. }
  296. delete [] tmpStr;
  297. }
  298. //Make sure directory exists
  299. WbemCreateDirectory(m_szLoggingDirectory);
  300. }
  301. HANDLE __Trace::get_logfile(const wchar_t * file_name )
  302. {
  303. AutoRevert revert;
  304. if (revert.self()==false)
  305. return INVALID_HANDLE_VALUE;
  306. HANDLE hTraceFile = INVALID_HANDLE_VALUE;
  307. bool bDoneWrite = false;
  308. //Keep trying to open the file
  309. while (!bDoneWrite)
  310. {
  311. while (hTraceFile == INVALID_HANDLE_VALUE)
  312. {
  313. if (WaitForSingleObject(buffers_lock_,-1)==WAIT_FAILED)
  314. return INVALID_HANDLE_VALUE;
  315. lstrcpy(m_szLogFileName, m_szLoggingDirectory);;
  316. lstrcat(m_szLogFileName, file_name);
  317. hTraceFile = ::CreateFileW( m_szLogFileName,
  318. GENERIC_WRITE,
  319. FILE_SHARE_READ | FILE_SHARE_DELETE,
  320. NULL,
  321. OPEN_ALWAYS,
  322. FILE_ATTRIBUTE_NORMAL,
  323. NULL );
  324. if ( hTraceFile == INVALID_HANDLE_VALUE )
  325. {
  326. ReleaseMutex(buffers_lock_);
  327. if (GetLastError() == ERROR_SHARING_VIOLATION)
  328. {
  329. Sleep(20);
  330. }
  331. else
  332. {
  333. return INVALID_HANDLE_VALUE;
  334. }
  335. }
  336. }
  337. ARMutex arm(buffers_lock_);
  338. //
  339. // Now move the file pointer to the end of the file
  340. //
  341. LARGE_INTEGER liSize;
  342. liSize.QuadPart = 0;
  343. if ( !::SetFilePointerEx( hTraceFile,
  344. liSize,
  345. NULL,
  346. FILE_END ) )
  347. {
  348. CloseHandle( hTraceFile );
  349. return INVALID_HANDLE_VALUE;
  350. }
  351. bDoneWrite = true;
  352. //Rename file if file length is exceeded
  353. LARGE_INTEGER liMaxSize;
  354. liMaxSize.QuadPart = m_dwMaxLogSize;
  355. if (GetFileSizeEx(hTraceFile, &liSize))
  356. {
  357. if (liSize.QuadPart > liMaxSize.QuadPart)
  358. {
  359. lstrcpy(m_szBackupFileName, m_szLogFileName);
  360. lstrcpy(m_szBackupFileName + lstrlen(m_szBackupFileName) - 3, __TEXT("lo_"));
  361. DeleteFile(m_szBackupFileName);
  362. if (MoveFile(m_szLogFileName, m_szBackupFileName) == 0)
  363. {
  364. if ( liSize.QuadPart < liMaxSize.QuadPart*2)
  365. return hTraceFile;
  366. else
  367. {
  368. CloseHandle(hTraceFile);
  369. return INVALID_HANDLE_VALUE;
  370. };
  371. }
  372. //Need to re-open the file!
  373. bDoneWrite = false;
  374. CloseHandle(hTraceFile);
  375. hTraceFile = INVALID_HANDLE_VALUE;
  376. }
  377. }
  378. }
  379. return hTraceFile;
  380. };
  381. int __Trace::Trace(char caller, const char *fmt, va_list &argptr)
  382. {
  383. HANDLE hTraceFile = INVALID_HANDLE_VALUE;
  384. try
  385. {
  386. if (caller >= (sizeof(m_szLogFileNames) / sizeof(char)))
  387. caller = 0;
  388. hTraceFile = get_logfile(m_szLogFileNames[caller]);
  389. if (hTraceFile == INVALID_HANDLE_VALUE)
  390. return 0;
  391. CCloseMe ch(hTraceFile);
  392. if (WaitForSingleObject(buffers_lock_,-1)==WAIT_FAILED)
  393. return 0;
  394. ARMutex arm(buffers_lock_);
  395. // Get time.
  396. // =========
  397. char timebuf[64];
  398. time_t now = time(0);
  399. struct tm *local = localtime(&now);
  400. if(local)
  401. {
  402. strcpy(timebuf, asctime(local));
  403. timebuf[strlen(timebuf) - 1] = 0; // O
  404. }
  405. else
  406. {
  407. strcpy(timebuf,"??");
  408. }
  409. //Put time in start of log
  410. sprintf(m_szTraceBuffer, "(%s.%d) : ", timebuf, GetTickCount());
  411. //Format the user string
  412. int nLen = strlen(m_szTraceBuffer);
  413. _vsnprintf(m_szTraceBuffer + nLen, 2047 - nLen, fmt, argptr);
  414. m_szTraceBuffer[2047] = '\0';
  415. //Unfortunately, lots of people only put \n in the string, so we need to convert the string...
  416. int nLen2 = 0;
  417. char *p = m_szTraceBuffer;
  418. char *p2 = m_szTraceBuffer2;
  419. for (; *p; p++,p2++,nLen2++)
  420. {
  421. if (*p == '\n')
  422. {
  423. *p2 = '\r';
  424. p2++;
  425. nLen2++;
  426. *p2 = '\n';
  427. }
  428. else
  429. {
  430. *p2 = *p;
  431. }
  432. }
  433. *p2 = '\0';
  434. //
  435. // Write to file :
  436. //
  437. DWORD dwWritten;
  438. ::WriteFile( hTraceFile, m_szTraceBuffer2, nLen2, &dwWritten, NULL);
  439. return 1;
  440. }
  441. catch(...)
  442. {
  443. return 0;
  444. }
  445. }
  446. BOOL __Trace::LoggingLevelEnabled(DWORD dwLevel)
  447. {
  448. DWORD dwCurTicks = GetTickCount();
  449. if (dwCurTicks - m_dwTimeLastRegCheck > REG_CHECK_INTERVAL)
  450. {
  451. ReReadRegistry();
  452. m_dwTimeLastRegCheck = dwCurTicks;
  453. }
  454. if ((dwLevel > m_dwLogging))
  455. return FALSE;
  456. else
  457. return TRUE;
  458. }
  459. BOOL LoggingLevelEnabled(DWORD dwLevel)
  460. {
  461. return __g_traceInfo.LoggingLevelEnabled(dwLevel);
  462. }
  463. int ErrorTrace(char caller, const char *fmt, ...)
  464. {
  465. if (__g_traceInfo.LoggingLevelEnabled(1))
  466. {
  467. va_list argptr;
  468. va_start(argptr, fmt);
  469. __g_traceInfo.Trace(caller, fmt, argptr);
  470. va_end(argptr);
  471. return 1;
  472. }
  473. else
  474. return 0;
  475. }
  476. int DebugTrace(char caller, const char *fmt, ...)
  477. {
  478. if (__g_traceInfo.LoggingLevelEnabled(2))
  479. {
  480. va_list argptr;
  481. va_start(argptr, fmt);
  482. __g_traceInfo.Trace(caller, fmt, argptr);
  483. va_end(argptr);
  484. return 1;
  485. }
  486. else
  487. return 0;
  488. }
  489. int CriticalFailADAPTrace(const char *string)
  490. //
  491. // The intention of this trace function is to be used in situations where catastrophic events
  492. // may have occured where the state of the heap may be in question. The function uses only
  493. // stack variables. Note that if a heap corruption has occured there is a small chance that
  494. // the global object __g_traceInfo may have been damaged.
  495. {
  496. return ErrorTrace(LOG_WMIADAP, "**CRITICAL FAILURE** %s", string);
  497. }
  498. // Helper for quick wchar to multibyte conversions. Caller muts
  499. // free the returned pointer
  500. BOOL POLARITY AllocWCHARToMBS( WCHAR* pWstr, char** ppStr )
  501. {
  502. if ( NULL == pWstr )
  503. {
  504. return FALSE;
  505. }
  506. // Get the length allocate space and copy the string
  507. long lLen = wcstombs(NULL, pWstr, 0);
  508. *ppStr = new char[lLen + 1];
  509. if (*ppStr == 0)
  510. return FALSE;
  511. wcstombs( *ppStr, pWstr, lLen + 1 );
  512. return TRUE;
  513. }
  514. LPTSTR GetWbemWorkDir( void )
  515. {
  516. LPTSTR pWorkDir = NULL;
  517. Registry r1(WBEM_REG_WBEM);
  518. if (r1.GetStr(__TEXT("Installation Directory"), &pWorkDir))
  519. {
  520. pWorkDir = new TCHAR[MAX_PATH + 1 + lstrlen(__TEXT("\\WBEM"))];
  521. if (pWorkDir == 0)
  522. return NULL;
  523. GetSystemDirectory(pWorkDir, MAX_PATH + 1);
  524. lstrcat(pWorkDir, __TEXT("\\WBEM"));
  525. }
  526. return pWorkDir;
  527. }
  528. LPTSTR GetWMIADAPCmdLine( int nExtra )
  529. {
  530. LPTSTR pWorkDir = GetWbemWorkDir();
  531. CVectorDeleteMe<TCHAR> vdm( pWorkDir );
  532. if ( NULL == pWorkDir )
  533. {
  534. return NULL;
  535. }
  536. // Buffer should be big enough for two quotes, WMIADAP.EXE and cmdline switches
  537. LPTSTR pCmdLine = new TCHAR[lstrlen( pWorkDir ) +
  538. lstrlen(__TEXT("\\\\?\\\\WMIADAP.EXE")) + nExtra + 1];
  539. if ( NULL == pCmdLine )
  540. {
  541. return NULL;
  542. }
  543. wsprintf( pCmdLine, __TEXT("\\\\?\\%s\\WMIADAP.EXE"), pWorkDir );
  544. return pCmdLine;
  545. }