windows-nt/Source/XPSP1/NT/base/screg/winreg/cntrtext/common/common.c
2020-09-26 16:20:57 +08:00

767 lines
22 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
common.c
Abstract:
Utility routines used by Lodctr and/or UnLodCtr
Author:
Bob Watson (a-robw) 12 Feb 93
Revision History:
--*/
#define UNICODE 1
#define _UNICODE 1
//
// "C" Include files
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
//
// Windows Include files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <winperf.h>
#include <tchar.h>
#include <initguid.h>
#include <guiddef.h>
#include "wmistr.h"
#include "evntrace.h"
//
// local include files
//
#define _INIT_WINPERFP_
#include "winperfp.h"
#include "ldprfmsg.h"
#include "common.h"
//
//
// Text string Constant definitions
//
LPCTSTR NamesKey = (LPCTSTR)TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
LPCTSTR DefaultLangId = (LPCTSTR)TEXT("009");
LPCTSTR DefaultLangTag = (LPCTSTR)TEXT("000");
LPCTSTR Counters = (LPCTSTR)TEXT("Counters");
LPCTSTR Help = (LPCTSTR)TEXT("Help");
LPCTSTR VersionStr = (LPCTSTR)TEXT("Version");
LPCTSTR LastHelp = (LPCTSTR)TEXT("Last Help");
LPCTSTR LastCounter = (LPCTSTR)TEXT("Last Counter");
LPCTSTR FirstHelp = (LPCTSTR)TEXT("First Help");
LPCTSTR cszFirstCounter = (LPCTSTR)TEXT("First Counter");
LPCTSTR Busy = (LPCTSTR)TEXT("Updating");
LPCTSTR Slash = (LPCTSTR)TEXT("\\");
LPCTSTR BlankString = (LPCTSTR)TEXT(" ");
LPCTSTR DriverPathRoot = (LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services");
LPCTSTR Performance = (LPCTSTR)TEXT("Performance");
LPCTSTR CounterNameStr = (LPCTSTR)TEXT("Counter ");
LPCTSTR HelpNameStr = (LPCTSTR)TEXT("Explain ");
LPCTSTR AddCounterNameStr = (LPCTSTR)TEXT("Addcounter ");
LPCTSTR AddHelpNameStr = (LPCTSTR)TEXT("Addexplain ");
LPCTSTR szObjectList = (LPCTSTR)TEXT("Object List");
LPCTSTR szLibraryValidationCode = (LPCTSTR)TEXT("Library Validation Code");
LPCTSTR szDisplayName = (LPCTSTR) TEXT("DisplayName");
LPCTSTR szPerfIniPath = (LPCTSTR) TEXT("PerfIni");
BOOLEAN g_bCheckTraceLevel = FALSE;
// Global (to this module) Buffers
//
static TCHAR DisplayStringBuffer[DISP_BUFF_SIZE];
static TCHAR TextFormat[DISP_BUFF_SIZE];
static HANDLE hMod = NULL; // process handle
static DWORD dwLastError = ERROR_SUCCESS;
HANDLE hEventLog = NULL;
HANDLE hLoadPerfMutex = NULL;
//
// local static data
//
static TCHAR cDoubleQuote = TEXT('\"');
BOOL
__stdcall
DllEntryPoint(
IN HANDLE DLLHandle,
IN DWORD Reason,
IN LPVOID ReservedAndUnused
)
{
BOOL bReturn = FALSE;
ReservedAndUnused;
DisableThreadLibraryCalls (DLLHandle);
switch(Reason) {
case DLL_PROCESS_ATTACH:
setlocale(LC_ALL, ".OCP");
hMod = DLLHandle; // use DLL handle , not APP handle
// register eventlog source
hEventLog = RegisterEventSourceW (
NULL, (LPCWSTR)L"LoadPerf");
bReturn = TRUE;
break;
case DLL_PROCESS_DETACH:
if (hEventLog != NULL) {
if (DeregisterEventSource(hEventLog)) {
hEventLog = NULL;
}
}
if (hLoadPerfMutex != NULL) {
CloseHandle(hLoadPerfMutex);
hLoadPerfMutex = NULL;
}
bReturn = TRUE;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
bReturn = TRUE;
break;
}
return bReturn;
}
LPCTSTR
GetStringResource (
UINT wStringId
)
/*++
Retrived UNICODE strings from the resource file for display
--*/
{
if (!hMod) {
hMod = (HINSTANCE)GetModuleHandle(NULL); // get instance ID of this module;
}
if (hMod) {
if ((LoadString(hMod, wStringId, DisplayStringBuffer, DISP_BUFF_SIZE)) > 0) {
return (LPTSTR)&DisplayStringBuffer[0];
} else {
dwLastError = GetLastError();
return BlankString;
}
} else {
return BlankString;
}
}
LPCWSTR
GetFormatResource (
UINT wStringId
)
/*++
Returns an ANSI string for use as a format string in a printf fn.
--*/
{
if (!hMod) {
hMod = (HINSTANCE)GetModuleHandle(NULL); // get instance ID of this module;
}
if (hMod) {
if ((LoadStringW(hMod, wStringId, TextFormat, DISP_BUFF_SIZE)) > 0) {
return (LPCTSTR)&TextFormat[0];
} else {
dwLastError = GetLastError();
return BlankString;
}
} else {
return BlankString;
}
}
VOID
DisplayCommandHelp (
UINT iFirstLine,
UINT iLastLine
)
/*++
DisplayCommandHelp
displays usage of command line arguments
Arguments
NONE
Return Value
NONE
--*/
{
UINT iThisLine;
WCHAR StringBuffer[DISP_BUFF_SIZE];
CHAR OemStringBuffer[DISP_BUFF_SIZE];
int nStringBufferLen;
int nOemStringBufferLen;
if (! hMod) {
hMod = (HINSTANCE) GetModuleHandle(NULL);
}
if (hMod) {
for (iThisLine = iFirstLine; iThisLine <= iLastLine; iThisLine++) {
ZeroMemory(StringBuffer, DISP_BUFF_SIZE * sizeof(WCHAR));
ZeroMemory(OemStringBuffer, DISP_BUFF_SIZE * sizeof(CHAR));
nStringBufferLen = LoadStringW(
hMod, iThisLine, StringBuffer, DISP_BUFF_SIZE);
if (nStringBufferLen > 0) {
nOemStringBufferLen = DISP_BUFF_SIZE;
WideCharToMultiByte(CP_OEMCP,
0,
StringBuffer,
nStringBufferLen,
OemStringBuffer,
nOemStringBufferLen,
NULL,
NULL);
fprintf (stdout, "\n%s", OemStringBuffer);
}
}
} // else do nothing
} // DisplayCommandHelp
BOOL
TrimSpaces (
IN OUT LPTSTR szString
)
/*++
Routine Description:
Trims leading and trailing spaces from szString argument, modifying
the buffer passed in
Arguments:
IN OUT LPTSTR szString
buffer to process
Return Value:
TRUE if string was modified
FALSE if not
--*/
{
LPTSTR szSource;
LPTSTR szDest;
LPTSTR szLast;
BOOL bChars;
szLast = szSource = szDest = szString;
bChars = FALSE;
while (*szSource != 0) {
// skip leading non-space chars
if (!_istspace(*szSource)) {
szLast = szDest;
bChars = TRUE;
}
if (bChars) {
// remember last non-space character
// copy source to destination & increment both
*szDest++ = *szSource++;
} else {
szSource++;
}
}
if (bChars) {
*++szLast = 0; // terminate after last non-space char
} else {
// string was all spaces so return an empty (0-len) string
*szString = 0;
}
return (szLast != szSource);
}
BOOL
IsDelimiter (
IN TCHAR cChar,
IN TCHAR cDelimiter
)
/*++
Routine Description:
compares the characte to the delimiter. If the delimiter is
a whitespace character then any whitespace char will match
otherwise an exact match is required
--*/
{
if (_istspace(cDelimiter)) {
// delimiter is whitespace so any whitespace char will do
return (_istspace(cChar));
} else {
// delimiter is not white space so use an exact match
return (cChar == cDelimiter);
}
}
LPCTSTR
GetItemFromString (
IN LPCTSTR szEntry,
IN DWORD dwItem,
IN TCHAR cDelimiter
)
/*++
Routine Description:
returns nth item from a list delimited by the cDelimiter Char.
Leaves (double)quoted strings intact.
Arguments:
IN LPCTSTR szEntry
Source string returned to parse
IN DWORD dwItem
1-based index indicating which item to return. (i.e. 1= first item
in list, 2= second, etc.)
IN TCHAR cDelimiter
character used to separate items. Note if cDelimiter is WhiteSpace
(e.g. a tab or a space) then any white space will serve as a delim.
Return Value:
pointer to buffer containing desired entry in string. Note, this
routine may only be called 4 times before the string
buffer is re-used. (i.e. don't use this function more than
4 times in single function call!!)
--*/
{
static TCHAR szReturnBuffer[4][MAX_PATH];
static LONG dwBuff;
LPTSTR szSource, szDest;
DWORD dwThisItem;
DWORD dwStrLeft;
dwBuff = ++dwBuff % 4; // wrap buffer index
szSource = (LPTSTR)szEntry;
szDest = &szReturnBuffer[dwBuff][0];
// clear previous contents
memset (szDest, 0, (MAX_PATH * sizeof(TCHAR)));
// find desired entry in string
dwThisItem = 1;
while (dwThisItem < dwItem) {
if (*szSource != 0) {
while (!IsDelimiter(*szSource, cDelimiter) && (*szSource != 0)) {
if (*szSource == cDoubleQuote) {
// if this is a quote, then go to the close quote
szSource++;
while ((*szSource != cDoubleQuote) && (*szSource != 0)) szSource++;
}
if (*szSource != 0) szSource++;
}
}
dwThisItem++;
if (*szSource != 0) szSource++;
}
// copy this entry to the return buffer
if (*szSource != 0) {
dwStrLeft = MAX_PATH-1;
while (!IsDelimiter(*szSource, cDelimiter) && (*szSource != 0)) {
if (*szSource == cDoubleQuote) {
// if this is a quote, then go to the close quote
// don't copy quotes!
szSource++;
while ((*szSource != cDoubleQuote) && (*szSource != 0)) {
*szDest++ = *szSource++;
dwStrLeft--;
if (!dwStrLeft) break; // dest is full (except for term NULL
}
if (*szSource != 0) szSource++;
} else {
*szDest++ = *szSource++;
dwStrLeft--;
if (!dwStrLeft) break; // dest is full (except for term NULL
}
}
*szDest = 0;
}
// remove any leading and/or trailing spaces
TrimSpaces (&szReturnBuffer[dwBuff][0]);
return &szReturnBuffer[dwBuff][0];
}
void
ReportLoadPerfEvent(
IN WORD EventType,
IN DWORD EventID,
IN DWORD dwDataCount,
IN DWORD dwData1,
IN DWORD dwData2,
IN DWORD dwData3,
IN DWORD dwData4,
IN WORD wStringCount,
IN LPWSTR szString1,
IN LPWSTR szString2,
IN LPWSTR szString3
)
{
DWORD dwData[5];
LPWSTR szMessageArray[4];
BOOL bResult = FALSE;
WORD wLocalStringCount = 0;
DWORD dwLastError = GetLastError();
if (dwDataCount > 4) dwDataCount = 4;
if (wStringCount > 3) wStringCount = 3;
if (dwDataCount > 0) dwData[0] = dwData1;
if (dwDataCount > 1) dwData[1] = dwData2;
if (dwDataCount > 2) dwData[2] = dwData3;
if (dwDataCount > 3) dwData[3] = dwData4;
dwDataCount *= sizeof(DWORD);
if (wStringCount > 0 && szString1) {
szMessageArray[wLocalStringCount] = szString1;
wLocalStringCount ++;
}
if (wStringCount > 1 && szString2) {
szMessageArray[wLocalStringCount] = szString2;
wLocalStringCount ++;
}
if (wStringCount > 2 && szString3) {
szMessageArray[wLocalStringCount] = szString3;
wLocalStringCount ++;
}
if (hEventLog == NULL) {
hEventLog = RegisterEventSourceW (NULL, (LPCWSTR)L"LoadPerf");
}
if (dwDataCount > 0 && wLocalStringCount > 0) {
bResult = ReportEventW(hEventLog,
EventType, // event type
0, // category (not used)
EventID, // event,
NULL, // SID (not used),
wLocalStringCount, // number of strings
dwDataCount, // sizeof raw data
szMessageArray, // message text array
(LPVOID) & dwData[0]); // raw data
}
else if (dwDataCount > 0) {
bResult = ReportEventW(hEventLog,
EventType, // event type
0, // category (not used)
EventID, // event,
NULL, // SID (not used),
0, // number of strings
dwDataCount, // sizeof raw data
NULL, // message text array
(LPVOID) & dwData[0]); // raw data
}
else if (wLocalStringCount > 0) {
bResult = ReportEventW(hEventLog,
EventType, // event type
0, // category (not used)
EventID, // event,
NULL, // SID (not used),
wLocalStringCount, // number of strings
0, // sizeof raw data
szMessageArray, // message text array
NULL); // raw data
}
else {
bResult = ReportEventW(hEventLog,
EventType, // event type
0, // category (not used)
EventID, // event,
NULL, // SID (not used),
0, // number of strings
0, // sizeof raw data
NULL, // message text array
NULL); // raw data
}
if (! bResult) {
DbgPrint("LOADPERF(0x%08X)::(%d,0x%08X,%d)(%d,%d,%d,%d,%d)(%d,%ws,%ws,%ws)\n",
GetCurrentThreadId(),
EventType, EventID, GetLastError(),
dwDataCount, dwData1, dwData2, dwData3, dwData4,
wStringCount, szString1, szString2, szString3);
}
SetLastError(dwLastError);
}
BOOLEAN LoadPerfGrabMutex()
{
BOOL bResult = TRUE;
HANDLE hLocalMutex = NULL;
DWORD dwWaitStatus = 0;
SECURITY_ATTRIBUTES SecurityAttributes;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea[3];
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY authWorld = SECURITY_WORLD_SID_AUTHORITY;
PSID psidSystem = NULL;
PSID psidAdmin = NULL;
PSID psidEveryone = NULL;
PACL pAcl = NULL;
if (hLoadPerfMutex == NULL) {
ZeroMemory(& ea, 3 * sizeof(EXPLICIT_ACCESS));
// Get the system sid
//
bResult = AllocateAndInitializeSid(& authNT,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
& psidSystem);
if (! bResult) {
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
// Set the access rights for system sid
//
ea[0].grfAccessPermissions = MUTEX_ALL_ACCESS;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR) psidSystem;
// Get the Admin sid
//
bResult = AllocateAndInitializeSid(& authNT,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
& psidAdmin);
if (! bResult) {
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
// Set the access rights for Admin sid
//
ea[1].grfAccessPermissions = MUTEX_ALL_ACCESS;
ea[1].grfAccessMode = SET_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[1].Trustee.ptstrName = (LPTSTR) psidAdmin;
// Get the World sid
//
bResult = AllocateAndInitializeSid(& authWorld,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
& psidEveryone);
if (! bResult) {
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
// Set the access rights for world
//
ea[2].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | MUTEX_MODIFY_STATE;
ea[2].grfAccessMode = SET_ACCESS;
ea[2].grfInheritance = NO_INHERITANCE;
ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[2].Trustee.ptstrName = (LPTSTR) psidEveryone;
// Create a new ACL that contains the new ACEs.
//
dwWaitStatus = SetEntriesInAcl(3, ea, NULL, & pAcl);
if (dwWaitStatus != ERROR_SUCCESS) {
bResult = FALSE;
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
// Initialize a security descriptor.
//
pSD = (PSECURITY_DESCRIPTOR)
LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSD == NULL) {
dwWaitStatus = GetLastError();
bResult = FALSE;
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
bResult = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
if (! bResult) {
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
// Add the ACL to the security descriptor.
//
bResult = SetSecurityDescriptorDacl(pSD, TRUE, pAcl, FALSE);
if (! bResult) {
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
goto Cleanup;
}
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
SecurityAttributes.bInheritHandle = TRUE;
SecurityAttributes.lpSecurityDescriptor = pSD;
__try {
hLocalMutex = CreateMutex(& SecurityAttributes,
FALSE,
TEXT("LOADPERF_MUTEX"));
if (hLocalMutex == NULL) {
bResult = FALSE;
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_ERROR),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
}
else if (InterlockedCompareExchangePointer(& hLoadPerfMutex,
hLocalMutex,
NULL) != NULL) {
CloseHandle(hLocalMutex);
hLocalMutex = NULL;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_FATAL),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
}
}
__try {
dwWaitStatus = WaitForSingleObject(hLoadPerfMutex, H_MUTEX_TIMEOUT);
} __except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwWaitStatus = GetLastError();
TRACE((WINPERF_DBG_TRACE_FATAL),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
}
if (dwWaitStatus != WAIT_OBJECT_0 && dwWaitStatus != WAIT_ABANDONED) {
bResult = FALSE;
TRACE((WINPERF_DBG_TRACE_FATAL),
(& LoadPerfGuid,
__LINE__,
LOADPERF_LOADPERFGRABMUTEX,
0,
dwWaitStatus,
NULL));
}
Cleanup:
if (psidSystem) FreeSid(psidSystem);
if (psidAdmin) FreeSid(psidAdmin);
if (psidEveryone) FreeSid(psidEveryone);
if (pAcl) LocalFree(pAcl);
if (pSD) LocalFree(pSD);
if (! bResult) SetLastError(dwWaitStatus);
return bResult ? TRUE : FALSE;
}