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

587 lines
23 KiB
C

/*++ BUILD Version: 0001 // Increment this if a change has global effects
Copyright (c) 2000 Microsoft Corporation
Module Name:
extlib.c
Abstract:
This file implements all the library routines operating on
extensible performance libraries.
Author:
JeePang
Revision History:
09/27/2000 - JeePang - Moved from perflib.c
--*/
#define UNICODE
//
// Include files
//
#pragma warning(disable:4306)
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntregapi.h>
#include <ntprfctr.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <winperf.h>
#include <rpc.h>
#include "regrpc.h"
#include "ntconreg.h"
#include "prflbmsg.h" // event log messages
#include "perflib.h"
#pragma warning(default:4306)
// default trusted file list
// all files presume to start with "perf"
// static LONGLONG llTrustedNamePrefix = 0x0066007200650050; // "Perf"
#define NAME_PREFIX L"Perf"
DWORD dwTrustedFileNames[] = {
0x0053004F, // "OS" for PerfOS.dll
0x0065004E, // "Ne" for PerfNet.dll
0x00720050, // "Pr" for PerfProc.dll
0x00690044 // "Di" for PerfDisk.dll
};
CONST DWORD dwTrustedFileNameCount =
sizeof(dwTrustedFileNames) / sizeof (dwTrustedFileNames[0]);
// there must be at least 8 chars in the name to be checked as trusted by
// default trusted file names are at least 8 chars in length
CONST DWORD dwMinTrustedFileNameLen = 6;
BOOL
ServiceIsTrustedByDefault (
LPCWSTR szServiceName
)
{
BOOL bReturn = FALSE;
DWORD dwNameToTest;
DWORD dwIdx;
if (szServiceName != NULL) {
// check for min size
dwIdx = 0;
while ((dwIdx < dwMinTrustedFileNameLen) && (szServiceName[dwIdx] > 0))
dwIdx++;
if (dwIdx == dwMinTrustedFileNameLen) {
// test first 4 bytes to see if they match
if (!wcsncmp(szServiceName, NAME_PREFIX, sizeof(LONGLONG))) {
// then see if the rest is in this list
dwNameToTest = * ((DWORD *)(szServiceName+4));
for (dwIdx = 0; dwIdx < dwTrustedFileNameCount; dwIdx++) {
if (dwNameToTest == dwTrustedFileNames[dwIdx]) {
// match found
bReturn = TRUE;
break;
} else {
// no match so continue
}
}
} else {
// no match so return false
}
} else {
// the name to be checked is too short so it mustn't be
// a trusted one.
}
} else {
// no string so return false
}
return bReturn;
}
DWORD
CloseExtObjectLibrary (
PEXT_OBJECT pObj,
BOOL bCloseNow
)
/*++
CloseExtObjectLibrary
Closes and unloads the specified performance counter library and
deletes all references to the functions.
The unloader is "lazy" in that it waits for the library to be
inactive for a specified time before unloading. This is due to the
fact that Perflib can not ever be certain that no thread will need
this library from one call to the next. In order to prevent "thrashing"
due to constantly loading and unloading of the library, the unloading
is delayed to make sure it's not really needed.
This function expects locked and exclusive access to the object while
it is opening. This must be provided by the calling function.
Arguments:
pObj -- pointer to the object information structure of the
perf object to close
bCloseNow -- the flag to indicate the library should be closed
immediately. This is the result of the calling function
closing the registry key.
--*/
{
DWORD Status = ERROR_SUCCESS;
LONGLONG TimeoutTime;
if (((dwThreadAndLibraryTimeout == 0) ||
(dwThreadAndLibraryTimeout == INFINITE)) && !bCloseNow) {
return Status;
}
if (pObj->hLibrary != NULL) {
// get current time to test timeout
TimeoutTime = GetTimeAsLongLong();
// timeout time is in ms
TimeoutTime -= dwThreadAndLibraryTimeout;
// don't close the library unless the object hasn't been accessed for
// a while or the caller is closing the key
if ((TimeoutTime > pObj->llLastUsedTime) || bCloseNow) {
// don't toss if this library has the "keep" flag set and this
// isn't a "close now" case
if (!bCloseNow && (pObj->dwFlags & PERF_EO_KEEP_RESIDENT)) {
// keep it loaded until the key is closed.
} else {
// then this is the last one to close the library
// free library
try {
// call close function for this DLL
Status = (*pObj->CloseProc)();
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_CLOSE_EXTOBJLIB,
ARG_TYPE_STR, Status,
// pObj->szCloseProcName,
// STRSIZE(pObj->szCloseProcName), NULL));
TRACE_STR(pObj->szCloseProcName), NULL));
}
FreeLibrary (pObj->hLibrary);
pObj->hLibrary = NULL;
// clear all pointers that are now invalid
pObj->OpenProc = NULL;
pObj->CollectProc = NULL;
pObj->QueryProc = NULL;
pObj->CloseProc = NULL;
InterlockedIncrement((LONG *)&pObj->dwCloseCount);
pObj->llLastUsedTime = 0;
}
}
Status = ERROR_SUCCESS;
} else {
// already closed
Status = ERROR_SUCCESS;
}
return Status;
}
DWORD
OpenExtObjectLibrary (
PEXT_OBJECT pObj
)
/*++
OpenExtObjectLibrary
Opens the specified library and looks up the functions used by
the performance library. If the library is successfully
loaded and opened then the open procedure is called to initialize
the object.
This function expects locked and exclusive access to the object while
it is opening. This must be provided by the calling function.
Arguments:
pObj -- pointer to the object information structure of the
perf object to close
--*/
{
DWORD FnStatus = ERROR_SUCCESS;
DWORD Status = ERROR_SUCCESS;
DWORD dwOpenEvent = 0;
DWORD dwType;
DWORD dwSize;
DWORD dwValue;
// variables used for event logging
DWORD dwDataIndex;
WORD wStringIndex;
ULONG_PTR dwRawDataDwords[8];
LPWSTR szMessageArray[8];
HANDLE hPerflibFuncTimer = NULL;
DLL_VALIDATION_DATA CurrentDllData;
OPEN_PROC_WAIT_INFO opwInfo;
UINT nErrorMode;
LPWSTR szServiceName;
DWORD szServiceNameSize;
BOOL bUseTimer;
// check to see if the library has already been opened
if (pObj->dwFlags & PERF_EO_DISABLED) return ERROR_SERVICE_DISABLED;
if (pObj->hLibrary == NULL) {
// library isn't loaded yet, so
// check to see if this function is enabled
dwType = 0;
dwSize = sizeof (dwValue);
dwValue = 0;
Status = PrivateRegQueryValueExW (
pObj->hPerfKey,
DisablePerformanceCounters,
NULL,
&dwType,
(LPBYTE)&dwValue,
&dwSize);
if ((Status == ERROR_SUCCESS) &&
(dwType == REG_DWORD) &&
(dwValue == 1)) {
// then DON'T Load this library
pObj->dwFlags |= PERF_EO_DISABLED;
} else {
// set the error status & the flag value
Status = ERROR_SUCCESS;
pObj->dwFlags &= ~PERF_EO_DISABLED;
}
szServiceName = pObj->szServiceName;
if (szServiceName == NULL) {
szServiceName = (LPWSTR) &NULL_STRING[0];
}
szServiceNameSize = WSTRSIZE(szServiceName);
if ((Status == ERROR_SUCCESS) &&
(pObj->LibData.FileSize > 0)) {
if (ServiceIsTrustedByDefault(pObj->szServiceName)) {
// then set as trusted and continue
pObj->dwFlags |= PERF_EO_TRUSTED;
} else {
// see if this is a trusted file or a file that has been updated
// get the file information
memset (&CurrentDllData, 0, sizeof(CurrentDllData));
Status = GetPerfDllFileInfo (
pObj->szLibraryName,
&CurrentDllData);
if (Status == ERROR_SUCCESS) {
// compare file data to registry data and update flags
if ((*(LONGLONG *)&pObj->LibData.CreationDate) ==
(*(LONGLONG *)&CurrentDllData.CreationDate) &&
(pObj->LibData.FileSize == CurrentDllData.FileSize)) {
pObj->dwFlags |= PERF_EO_TRUSTED;
} else if (lEventLogLevel >= LOG_USER) {
TRACE((WINPERF_DBG_TRACE_WARNING),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_TYPE_WSTR, 0, szServiceName,
szServiceNameSize, NULL));
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE, // error type
0, // category (not used)
(DWORD)PERFLIB_NOT_TRUSTED_FILE, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
0, // sizeof raw data
szMessageArray, // message text array
NULL); // raw data
}
}
}
}
if ((Status == ERROR_SUCCESS) && (!(pObj->dwFlags & PERF_EO_DISABLED))) {
// go ahead and load it
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
// then load library & look up functions
pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (pObj->hLibrary != NULL) {
// lookup function names
pObj->OpenProc = (OPENPROC)GetProcAddress(
pObj->hLibrary, pObj->szOpenProcName);
if (pObj->OpenProc == NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
0, szServiceName, szServiceNameSize,
TRACE_STR(pObj->szOpenProcName), NULL));
if (lEventLogLevel >= LOG_USER) {
WCHAR wszProcName[MAX_PATH+1];
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(ULONG_PTR)Status;
wcstombs(pObj->szOpenProcName, wszProcName, MAX_PATH);
szMessageArray[wStringIndex++] = &wszProcName[0];
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)PERFLIB_OPEN_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
DisablePerfLibrary (pObj);
}
if (Status == ERROR_SUCCESS) {
if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
pObj->QueryProc = (QUERYPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
} else {
pObj->CollectProc = (COLLECTPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
}
if (pObj->CollectProc == NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
0, szServiceName, szServiceNameSize,
TRACE_STR(pObj->szCollectProcName), NULL));
if (lEventLogLevel >= LOG_USER) {
WCHAR wszProcName[MAX_PATH+1];
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(ULONG_PTR)Status;
wcstombs(pObj->szCollectProcName,
wszProcName, MAX_PATH);
szMessageArray[wStringIndex++] = &wszProcName[0];
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)PERFLIB_COLLECT_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
DisablePerfLibrary (pObj);
}
}
if (Status == ERROR_SUCCESS) {
pObj->CloseProc = (CLOSEPROC)GetProcAddress (
pObj->hLibrary, pObj->szCloseProcName);
if (pObj->CloseProc == NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
0, szServiceName, szServiceNameSize,
TRACE_STR(pObj->szCloseProcName), NULL));
if (lEventLogLevel >= LOG_USER) {
WCHAR wszProcName[MAX_PATH+1];
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(ULONG_PTR)Status;
wcstombs(pObj->szCollectProcName,
wszProcName, MAX_PATH);
szMessageArray[wStringIndex++] = &wszProcName[0];
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)PERFLIB_CLOSE_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
DisablePerfLibrary (pObj);
}
}
bUseTimer = TRUE; // default
if (!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) {
if (pObj->dwFlags & PERF_EO_TRUSTED) {
bUseTimer = FALSE; // Trusted DLL's are not timed
}
} else {
// disable DLL testing
bUseTimer = FALSE; // Timing is disabled as well
}
if (Status == ERROR_SUCCESS) {
try {
// start timer
opwInfo.pNext = NULL;
opwInfo.szLibraryName = pObj->szLibraryName;
opwInfo.szServiceName = pObj->szServiceName;
opwInfo.dwWaitTime = pObj->dwOpenTimeout;
opwInfo.dwEventMsg = PERFLIB_OPEN_PROC_TIMEOUT;
opwInfo.pData = (LPVOID)pObj;
if (bUseTimer) {
hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
// if no timer, continue anyway, even though things may
// hang, it's better than not loading the DLL since they
// usually load OK
//
if (hPerflibFuncTimer == NULL) {
// unable to get a timer entry
TRACE((WINPERF_DBG_TRACE_WARNING),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB, 0, 0, NULL));
}
} else {
hPerflibFuncTimer = NULL;
}
// call open procedure to initialize DLL
FnStatus = (*pObj->OpenProc)(pObj->szLinkageString);
// check the result.
if (FnStatus != ERROR_SUCCESS) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
FnStatus, szServiceName, szServiceNameSize,
pObj->szLinkageString, (pObj->szLinkageString) ?
WSTRSIZE(pObj->szLinkageString) : 0, NULL));
dwOpenEvent = PERFLIB_OPEN_PROC_FAILURE;
} else {
InterlockedIncrement((LONG *)&pObj->dwOpenCount);
}
} except (EXCEPTION_EXECUTE_HANDLER) {
FnStatus = GetExceptionCode();
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXTOBJLIB,
ARG_DEF(ARG_TYPE_WSTR, 1), FnStatus,
szServiceName, szServiceNameSize, NULL));
dwOpenEvent = PERFLIB_OPEN_PROC_EXCEPTION;
}
if (hPerflibFuncTimer != NULL) {
// kill timer
Status = KillPerflibFunctionTimer (hPerflibFuncTimer);
hPerflibFuncTimer = NULL;
}
if (FnStatus != ERROR_SUCCESS) {
DWORD ReportError = 1;
if (dwOpenEvent == PERFLIB_OPEN_PROC_EXCEPTION) {
DisablePerfLibrary (pObj);
}
else {
ReportError = PerfUpdateErrorCount(pObj, 1);
}
if ((ReportError > 0) && (lEventLogLevel >= LOG_USER)) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(ULONG_PTR)FnStatus;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
ReportEventW (hEventLog,
(WORD)EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
dwOpenEvent, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
else {
PerfUpdateErrorCount(pObj, 0);
}
}
if (FnStatus != ERROR_SUCCESS) {
// clear fields
pObj->OpenProc = NULL;
pObj->CollectProc = NULL;
pObj->QueryProc = NULL;
pObj->CloseProc = NULL;
if (pObj->hLibrary != NULL) {
FreeLibrary (pObj->hLibrary);
pObj->hLibrary = NULL;
}
Status = FnStatus;
} else {
pObj->llLastUsedTime = GetTimeAsLongLong();
}
} else {
Status = GetLastError();
}
SetErrorMode (nErrorMode);
}
} else {
// else already open so bump the ref count
pObj->llLastUsedTime = GetTimeAsLongLong();
}
return Status;
}