windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/wbemcomn/wbemutil.cpp
2020-09-26 16:20:57 +08:00

655 lines
14 KiB
C++

/*++
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 <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <wbemutil.h>
#include <corex.h>
#include "reg.h"
#include <TCHAR.H>
#include "sync.h"
#include <ARRTEMPL.H>
class AutoRevert
{
private:
HANDLE oldToken_;
bool self_;
public:
AutoRevert();
~AutoRevert();
void dismiss();
bool self(){ return self_;}
};
AutoRevert::AutoRevert():oldToken_(NULL),self_(true)
{
if (OpenThreadToken(GetCurrentThread(),TOKEN_IMPERSONATE,TRUE,&oldToken_))
{
RevertToSelf();
}else
{
if (GetLastError() != ERROR_NO_TOKEN)
self_ = false;
};
}
AutoRevert::~AutoRevert()
{
dismiss();
}
void AutoRevert::dismiss()
{
if (oldToken_)
{
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 iswdigit(c);
}
BOOL IsValidElementName( LPCWSTR wszName )
{
if(wszName[0] == 0)
return FALSE;
if(wszName[0] == '_')
return FALSE;
const WCHAR* pwc = wszName;
// 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)
{
if(!isunialphanum(*pwc))
return FALSE;
pwc++;
}
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, BOOL bAllowUnderscore )
{
if(wszName[0] == 0)
return FALSE;
if(!bAllowUnderscore && wszName[0] == '_')
return FALSE;
const WCHAR* pwc = wszName;
// 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)
{
if(!isunialphanum(*pwc))
return FALSE;
pwc++;
}
if (iswspace(*(pwc-1)))
return FALSE;
if(!bAllowUnderscore && pwc[-1] == '_')
return FALSE;
return TRUE;
}
BLOB POLARITY BlobCopy(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);
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")
};
__Trace __g_traceInfo;
__Trace::__Trace()
: m_dwLogging(1),
m_dwMaxLogSize(65536),
m_dwTimeLastRegCheck(GetTickCount())
{
buffers_lock_ = CreateMutex(0,0,0);
ReadLogDirectory();
ReReadRegistry();
}
__Trace::~__Trace()
{
CloseHandle(buffers_lock_);
};
void __Trace::ReReadRegistry()
{
Registry r(WBEM_REG_WINMGMT);
//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)
{
lstrcpy(m_szLoggingDirectory, __TEXT("c:\\"));
}
else
{
lstrcat(m_szLoggingDirectory, __TEXT("\\WBEM\\Logs\\"));
r.SetStr(__TEXT("Logging Directory"), m_szLoggingDirectory);
}
}
else
{
lstrcpy(m_szLoggingDirectory, tmpStr);
//make sure there is a '\' on the end of the path...
if (m_szLoggingDirectory[lstrlen(m_szLoggingDirectory) - 1] != '\\')
{
lstrcat(m_szLoggingDirectory, __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;
lstrcpy(m_szLogFileName, m_szLoggingDirectory);;
lstrcat(m_szLogFileName, file_name);
hTraceFile = ::CreateFileW( m_szLogFileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
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)
{
lstrcpy(m_szBackupFileName, m_szLogFileName);
lstrcpy(m_szBackupFileName + lstrlen(m_szBackupFileName) - 3, __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)
{
strcpy(timebuf, asctime(local));
timebuf[strlen(timebuf) - 1] = 0; // O
}
else
{
strcpy(timebuf,"??");
}
//Put time in start of log
sprintf(m_szTraceBuffer, "(%s.%d) : ", timebuf, GetTickCount());
//Format the user string
int nLen = strlen(m_szTraceBuffer);
_vsnprintf(m_szTraceBuffer + nLen, 2047 - nLen, fmt, argptr);
m_szTraceBuffer[2047] = '\0';
//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)
{
DWORD dwCurTicks = GetTickCount();
if (dwCurTicks - m_dwTimeLastRegCheck > REG_CHECK_INTERVAL)
{
ReReadRegistry();
m_dwTimeLastRegCheck = dwCurTicks;
}
if ((dwLevel > m_dwLogging))
return FALSE;
else
return TRUE;
}
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_WBEM);
if (r1.GetStr(__TEXT("Installation Directory"), &pWorkDir))
{
pWorkDir = new TCHAR[MAX_PATH + 1 + lstrlen(__TEXT("\\WBEM"))];
if (pWorkDir == 0)
return NULL;
GetSystemDirectory(pWorkDir, MAX_PATH + 1);
lstrcat(pWorkDir, __TEXT("\\WBEM"));
}
return pWorkDir;
}
LPTSTR GetWMIADAPCmdLine( int nExtra )
{
LPTSTR pWorkDir = GetWbemWorkDir();
CVectorDeleteMe<TCHAR> vdm( pWorkDir );
if ( NULL == pWorkDir )
{
return NULL;
}
// Buffer should be big enough for two quotes, WMIADAP.EXE and cmdline switches
LPTSTR pCmdLine = new TCHAR[lstrlen( pWorkDir ) +
lstrlen(__TEXT("\\\\?\\\\WMIADAP.EXE")) + nExtra + 1];
if ( NULL == pCmdLine )
{
return NULL;
}
wsprintf( pCmdLine, __TEXT("\\\\?\\%s\\WMIADAP.EXE"), pWorkDir );
return pCmdLine;
}