/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: WBEMUTIL.CPP Abstract: General utility functions. History: a-raymcc 17-Apr-96 Created. --*/ #include "precomp.h" #include #include #include #include #include #include #include "reg.h" #include "sync.h" #include #include static BOOL g_bMachineDown = FALSE; BOOL WbemGetMachineShutdown() { return g_bMachineDown; }; BOOL WbemSetMachineShutdown(BOOL bVal) { BOOL bTmp = g_bMachineDown; g_bMachineDown = bVal; return bTmp; } class AutoRevert { private: HANDLE oldToken_; BOOL SetThrTokResult_; bool self_; public: AutoRevert(); ~AutoRevert(); void dismiss(); bool self(){ return self_;} }; AutoRevert::AutoRevert():oldToken_(NULL),self_(true),SetThrTokResult_(FALSE) { if (OpenThreadToken(GetCurrentThread(),TOKEN_IMPERSONATE,TRUE,&oldToken_)) { RevertToSelf(); } else { if (GetLastError() != ERROR_NO_TOKEN) self_ = false; }; } AutoRevert::~AutoRevert() { dismiss(); } void AutoRevert::dismiss() { if (oldToken_) { // if the handle has been opened with TOKEN_IMPERSONATE // and if nobody has touched the SD for the ETHREAD object, this will work SetThrTokResult_ = SetThreadToken(NULL,oldToken_); CloseHandle(oldToken_); } } //*************************************************************************** // // BOOL isunialpha(wchar_t c) // // Used to test if a wide character is a unicode character or underscore. // // Parameters: // c = The character being tested. // Return value: // TRUE if OK. // //*************************************************************************** BOOL POLARITY isunialpha(wchar_t c) { if(c == 0x5f || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a) || (0x80 <= c && c <= 0xfffd)) return TRUE; else return FALSE; } //*************************************************************************** // // BOOL isunialphanum(char_t c) // // Used to test if a wide character is string suitable for identifiers. // // Parameters: // pwc = The character being tested. // Return value: // TRUE if OK. // //*************************************************************************** BOOL POLARITY isunialphanum(wchar_t c) { if(isunialpha(c)) return TRUE; else return wbem_iswdigit(c); } BOOL IsValidElementName( LPCWSTR wszName, DWORD MaxAllow ) { if(wszName[0] == 0) return FALSE; if(wszName[0] == '_') return FALSE; const WCHAR* pwc = wszName; LPCWSTR pTail = wszName+MaxAllow+1; // Check the first letter // ====================== // this is for compatibility with IWbemPathParser if (iswspace(pwc[0])) return FALSE; if(!isunialpha(*pwc)) return FALSE; pwc++; // Check the rest // ============== while(*pwc && (pwc < pTail)) { if(!isunialphanum(*pwc)) return FALSE; pwc++; } if ( pwc == pTail ) return FALSE; if (iswspace(*(pwc-1))) return FALSE; if(pwc[-1] == '_') return FALSE; return TRUE; } // Can't use overloading and/or default parameters because // "C" files use these guys. No, I'm not happy about // this! BOOL IsValidElementName2( LPCWSTR wszName,DWORD MaxAllow, BOOL bAllowUnderscore ) { if(wszName[0] == 0) return FALSE; if(!bAllowUnderscore && wszName[0] == '_') return FALSE; const WCHAR* pwc = wszName; LPCWSTR pTail = wszName+MaxAllow+1; // Check the first letter // ====================== // this is for compatibility with IWbemPathParser if (iswspace(pwc[0])) return FALSE; if(!isunialpha(*pwc)) return FALSE; pwc++; // Check the rest // ============== while(*pwc && (pwc < pTail)) { if(!isunialphanum(*pwc)) return FALSE; pwc++; } if ( pwc == pTail ) return FALSE; if (iswspace(*(pwc-1))) return FALSE; if(!bAllowUnderscore && pwc[-1] == '_') return FALSE; return TRUE; } BLOB POLARITY BlobCopy(const BLOB *pSrc) { BLOB Blob; BYTE *p = new BYTE[pSrc->cbSize]; // Check for allocation failure if ( NULL == p ) { throw CX_MemoryException(); } Blob.cbSize = pSrc->cbSize; Blob.pBlobData = p; memcpy(p, pSrc->pBlobData, Blob.cbSize); return Blob; } void POLARITY BlobAssign(BLOB *pBlob, LPVOID pBytes, DWORD dwCount, BOOL bAcquire) { BYTE *pSrc = 0; if (bAcquire) pSrc = (BYTE *) pBytes; else { pSrc = new BYTE[dwCount]; // Check for allocation failure if ( NULL == pSrc ) { throw CX_MemoryException(); } memcpy(pSrc, pBytes, dwCount); } pBlob->cbSize = dwCount; pBlob->pBlobData = pSrc; } void POLARITY BlobClear(BLOB *pSrc) { if (pSrc->pBlobData) delete pSrc->pBlobData; pSrc->pBlobData = 0; pSrc->cbSize = 0; } class __Trace { struct ARMutex { HANDLE h_; ARMutex(HANDLE h):h_(h){} ~ARMutex(){ ReleaseMutex(h_);} }; public: enum { REG_CHECK_INTERVAL =1000 * 60 }; DWORD m_dwLogging; DWORD m_dwMaxLogSize; DWORD m_dwTimeLastRegCheck; wchar_t m_szLoggingDirectory[MAX_PATH+1]; char m_szTraceBuffer[2048]; char m_szTraceBuffer2[4096]; wchar_t m_szBackupFileName[MAX_PATH+1]; wchar_t m_szLogFileName[MAX_PATH+1]; static const wchar_t *m_szLogFileNames[]; BOOL LoggingLevelEnabled(DWORD dwLevel); DWORD GetLoggingLevel(); int Trace(char caller, const char *fmt, va_list &argptr); __Trace(); ~__Trace(); HANDLE get_logfile(const wchar_t * name ); private: void ReadLogDirectory(); void ReReadRegistry(); HANDLE buffers_lock_; }; const wchar_t * __Trace::m_szLogFileNames[] = { FILENAME_PREFIX_CORE TEXT(".log"), FILENAME_PREFIX_EXE TEXT(".log"), FILENAME_PREFIX_ESS TEXT(".log"), FILENAME_PREFIX_CLI_MARSH TEXT(".log"), FILENAME_PREFIX_SERV_MARSH TEXT(".log"), FILENAME_PREFIX_QUERY TEXT(".log"), FILENAME_PROFIX_MOFCOMP TEXT(".log"), FILENAME_PROFIX_EVENTLOG TEXT(".log"), FILENAME_PROFIX_WBEMDISP TEXT(".log"), FILENAME_PROFIX_STDPROV TEXT(".log"), FILENAME_PROFIX_WMIPROV TEXT(".log"), FILENAME_PROFIX_WMIOLEDB TEXT(".log"), FILENAME_PREFIX_WMIADAP TEXT(".log"), FILENAME_PREFIX_REPDRV TEXT(".log"), FILENAME_PREFIX_PROVSS TEXT(".log"), FILENAME_PREFIX_EVTPROV TEXT(".log"), FILENAME_PREFIX_VIEWPROV TEXT(".log"), FILENAME_PREFIX_DSPROV TEXT(".log"), FILENAME_PREFIX_SNMPPROV TEXT(".log"), FILENAME_PREFIX_PROVTHRD TEXT(".log") }; __Trace __g_traceInfo; __Trace::__Trace() : m_dwLogging(1), m_dwMaxLogSize(65536), m_dwTimeLastRegCheck(GetTickCount()) { buffers_lock_ = CreateMutexA(0,0,0); if (NULL == buffers_lock_) { CStaticCritSec::SetFailure(); return; } ReadLogDirectory(); ReReadRegistry(); } __Trace::~__Trace() { if (buffers_lock_) CloseHandle(buffers_lock_); }; void __Trace::ReReadRegistry() { Registry r(WBEM_REG_WINMGMT, KEY_READ); //Get the logging level if (r.GetDWORDStr(TEXT("Logging"), &m_dwLogging) != Registry::no_error) { m_dwLogging = 1; r.SetDWORDStr(TEXT("Logging"), m_dwLogging); } //Get the maximum log file size if (r.GetDWORDStr(TEXT("Log File Max Size"), &m_dwMaxLogSize) != Registry::no_error) { m_dwMaxLogSize = 65536; r.SetDWORDStr(TEXT("Log File Max Size"), m_dwMaxLogSize); } } void __Trace::ReadLogDirectory() { Registry r(WBEM_REG_WINMGMT); //Retrieve the logging directory TCHAR *tmpStr = 0; if ((r.GetStr(TEXT("Logging Directory"), &tmpStr) == Registry::failed) || (lstrlen(tmpStr) > (MAX_PATH))) { delete [] tmpStr; //Just in case someone was trying for a buffer overrun with a long path in the registry... if (GetSystemDirectory(m_szLoggingDirectory, MAX_PATH+1) == 0) { StringCchCopy(m_szLoggingDirectory, MAX_PATH+1, TEXT("c:\\")); } else { StringCchCat(m_szLoggingDirectory, MAX_PATH+1, TEXT("\\WBEM\\Logs\\")); r.SetStr(TEXT("Logging Directory"), m_szLoggingDirectory); } } else { StringCchCopy(m_szLoggingDirectory, MAX_PATH+1, tmpStr); //make sure there is a '\' on the end of the path... if (m_szLoggingDirectory[lstrlen(m_szLoggingDirectory) - 1] != '\\') { StringCchCat(m_szLoggingDirectory, MAX_PATH+1,TEXT("\\")); r.SetStr(TEXT("Logging Directory"), m_szLoggingDirectory); } delete [] tmpStr; } //Make sure directory exists WbemCreateDirectory(m_szLoggingDirectory); } HANDLE __Trace::get_logfile(const wchar_t * file_name ) { AutoRevert revert; if (revert.self()==false) return INVALID_HANDLE_VALUE; HANDLE hTraceFile = INVALID_HANDLE_VALUE; bool bDoneWrite = false; //Keep trying to open the file while (!bDoneWrite) { while (hTraceFile == INVALID_HANDLE_VALUE) { if (WaitForSingleObject(buffers_lock_,-1)==WAIT_FAILED) return INVALID_HANDLE_VALUE; StringCchCopy(m_szLogFileName, MAX_PATH+1, m_szLoggingDirectory);; StringCchCat(m_szLogFileName, MAX_PATH+1, file_name); hTraceFile = ::CreateFileW( m_szLogFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, NULL ); if ( hTraceFile == INVALID_HANDLE_VALUE ) { ReleaseMutex(buffers_lock_); if (GetLastError() == ERROR_SHARING_VIOLATION) { Sleep(20); } else { return INVALID_HANDLE_VALUE; } } } ARMutex arm(buffers_lock_); // // Now move the file pointer to the end of the file // LARGE_INTEGER liSize; liSize.QuadPart = 0; if ( !::SetFilePointerEx( hTraceFile, liSize, NULL, FILE_END ) ) { CloseHandle( hTraceFile ); return INVALID_HANDLE_VALUE; } bDoneWrite = true; //Rename file if file length is exceeded LARGE_INTEGER liMaxSize; liMaxSize.QuadPart = m_dwMaxLogSize; if (GetFileSizeEx(hTraceFile, &liSize)) { if (liSize.QuadPart > liMaxSize.QuadPart) { StringCchCopy(m_szBackupFileName, MAX_PATH+1, m_szLogFileName); StringCchCopy(m_szBackupFileName + lstrlen(m_szBackupFileName) - 3, MAX_PATH+1, TEXT("lo_")); DeleteFile(m_szBackupFileName); if (MoveFile(m_szLogFileName, m_szBackupFileName) == 0) { if ( liSize.QuadPart < liMaxSize.QuadPart*2) return hTraceFile; else { CloseHandle(hTraceFile); return INVALID_HANDLE_VALUE; }; } //Need to re-open the file! bDoneWrite = false; CloseHandle(hTraceFile); hTraceFile = INVALID_HANDLE_VALUE; } } } return hTraceFile; }; int __Trace::Trace(char caller, const char *fmt, va_list &argptr) { HANDLE hTraceFile = INVALID_HANDLE_VALUE; try { if (caller >= (sizeof(m_szLogFileNames) / sizeof(char))) caller = 0; hTraceFile = get_logfile(m_szLogFileNames[caller]); if (hTraceFile == INVALID_HANDLE_VALUE) return 0; CCloseMe ch(hTraceFile); if (WaitForSingleObject(buffers_lock_,-1)==WAIT_FAILED) return 0; ARMutex arm(buffers_lock_); // Get time. // ========= char timebuf[64]; time_t now = time(0); struct tm *local = localtime(&now); if(local) { StringCchCopyA(timebuf, 64, asctime(local)); timebuf[strlen(timebuf) - 1] = 0; // O } else { StringCchCopyA(timebuf, 64, "??"); } //Put time in start of log StringCchPrintfA(m_szTraceBuffer, 2048, "(%s.%d) : ", timebuf, GetTickCount()); //Format the user string int nLen = strlen(m_szTraceBuffer); StringCchVPrintfA(m_szTraceBuffer + nLen, 2048 - nLen, fmt, argptr); //Unfortunately, lots of people only put \n in the string, so we need to convert the string... int nLen2 = 0; char *p = m_szTraceBuffer; char *p2 = m_szTraceBuffer2; for (; *p; p++,p2++,nLen2++) { if (*p == '\n') { *p2 = '\r'; p2++; nLen2++; *p2 = '\n'; } else { *p2 = *p; } } *p2 = '\0'; // // Write to file : // DWORD dwWritten; ::WriteFile( hTraceFile, m_szTraceBuffer2, nLen2, &dwWritten, NULL); return 1; } catch(...) { return 0; } } BOOL __Trace::LoggingLevelEnabled(DWORD dwLevel) { if (!WbemGetMachineShutdown()) // prevent touching registry during machine shutdown { DWORD dwCurTicks = GetTickCount(); if (dwCurTicks - m_dwTimeLastRegCheck > REG_CHECK_INTERVAL) { ReReadRegistry(); m_dwTimeLastRegCheck = dwCurTicks; } } if ((dwLevel > m_dwLogging)) return FALSE; else return TRUE; } DWORD __Trace::GetLoggingLevel() { if (!WbemGetMachineShutdown()) // prevent touching registry during machine shutdown { DWORD dwCurTicks = GetTickCount(); if (dwCurTicks - m_dwTimeLastRegCheck > REG_CHECK_INTERVAL) { ReReadRegistry(); m_dwTimeLastRegCheck = dwCurTicks; } } return m_dwLogging; }; DWORD GetLoggingLevelEnabled() { return __g_traceInfo.GetLoggingLevel(); } BOOL LoggingLevelEnabled(DWORD dwLevel) { return __g_traceInfo.LoggingLevelEnabled(dwLevel); } int ErrorTrace(char caller, const char *fmt, ...) { if (__g_traceInfo.LoggingLevelEnabled(1)) { va_list argptr; va_start(argptr, fmt); __g_traceInfo.Trace(caller, fmt, argptr); va_end(argptr); return 1; } else return 0; } int DebugTrace(char caller, const char *fmt, ...) { if (__g_traceInfo.LoggingLevelEnabled(2)) { va_list argptr; va_start(argptr, fmt); __g_traceInfo.Trace(caller, fmt, argptr); va_end(argptr); return 1; } else return 0; } int CriticalFailADAPTrace(const char *string) // // The intention of this trace function is to be used in situations where catastrophic events // may have occured where the state of the heap may be in question. The function uses only // stack variables. Note that if a heap corruption has occured there is a small chance that // the global object __g_traceInfo may have been damaged. { return ErrorTrace(LOG_WMIADAP, "**CRITICAL FAILURE** %s", string); } // Helper for quick wchar to multibyte conversions. Caller muts // free the returned pointer BOOL POLARITY AllocWCHARToMBS( WCHAR* pWstr, char** ppStr ) { if ( NULL == pWstr ) { return FALSE; } // Get the length allocate space and copy the string long lLen = wcstombs(NULL, pWstr, 0); *ppStr = new char[lLen + 1]; if (*ppStr == 0) return FALSE; wcstombs( *ppStr, pWstr, lLen + 1 ); return TRUE; } LPTSTR GetWbemWorkDir( void ) { LPTSTR pWorkDir = NULL; Registry r1(WBEM_REG_WINMGMT); if (r1.GetStr(TEXT("Working Directory"), &pWorkDir)) { size_t bufferLength = MAX_PATH + 1 + lstrlen(TEXT("\\WBEM")); wmilib::auto_buffer p(new TCHAR[bufferLength]); if (NULL == p.get()) return NULL; DWORD dwRet = GetSystemDirectory(p.get(), MAX_PATH + 1); if (0 == dwRet) return NULL; if (dwRet > MAX_PATH) { bufferLength = 4 + 1 + dwRet; p.reset(new TCHAR[bufferLength]); if (NULL == p.get()) return NULL; if (0 == GetSystemDirectory(p.get(), dwRet + 1)) return NULL; } StringCchCat(p.get(), bufferLength, TEXT("\\WBEM")); pWorkDir = p.release(); } return pWorkDir; } LPTSTR GetWMIADAPCmdLine( int nExtra ) { LPTSTR pWorkDir = GetWbemWorkDir(); CVectorDeleteMe vdm( pWorkDir ); if ( NULL == pWorkDir ) { return NULL; } // Buffer should be big enough for two quotes, WMIADAP.EXE and cmdline switches size_t bufferLength = lstrlen( pWorkDir ) + lstrlen(TEXT("\\\\?\\\\WMIADAP.EXE")) + nExtra + 1; LPTSTR pCmdLine = new TCHAR[bufferLength]; if ( NULL == pCmdLine ) { return NULL; } StringCchPrintf( pCmdLine,bufferLength, TEXT("\\\\?\\%s\\WMIADAP.EXE"), pWorkDir ); return pCmdLine; } BOOL IsNtSetupRunning() { HKEY hKey; long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,L"system\\Setup",0, KEY_READ, &hKey); if(ERROR_SUCCESS != lRes) return FALSE; DWORD dwSetupRunning; DWORD dwLen = sizeof(DWORD); lRes = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, NULL,(LPBYTE)&dwSetupRunning, &dwLen); RegCloseKey(hKey); if(lRes == ERROR_SUCCESS && (dwSetupRunning == 1)) { return TRUE; } return FALSE; }