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.
 
 
 
 
 
 

567 lines
13 KiB

#include "npstub.h"
#include <netspi.h>
#include <npord.h>
#include <nphook.h>
#include <npstubx.h> /* message defs, class name */
#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
HINSTANCE hInstance = NULL;
HWND hwndMonitor = NULL;
CRITICAL_SECTION critsec;
ATOM aClass = NULL;
#define ENTERCRITICAL EnterCriticalSection(&::critsec);
#define LEAVECRITICAL LeaveCriticalSection(&::critsec);
UINT cCallsInProgress = 0;
BOOL fShouldUnload = FALSE;
/* This chunk of code invokes the entrypoint hooking feature of MPR. We hook
* things and immediately unhook ourselves. We don't really want to hook
* any functionality, this is just a way to kick MPR so he'll redetermine
* the capabilities (via NPGetCaps) of all the net providers, including
* ours.
*/
F_NPSHookMPR HookHookMPR;
F_UnHookMPR HookUnHookMPR;
F_LoadLibrary HookLoadLibrary;
F_FreeLibrary HookFreeLibrary;
F_GetProcAddress HookGetProcAddress;
F_LoadLibrary16 HookWMLoadWinnet16;
F_FreeLibrary16 HookWMFreeWinnet16;
F_GetProcAddressByName16 HookWMGetProcAddressByName;
F_GetProcAddressByOrdinal16 HookWMGetProcAddressByOrdinal;
MPRCALLS MPRCalls = { HookHookMPR,
HookUnHookMPR,
HookLoadLibrary,
HookFreeLibrary,
HookGetProcAddress,
HookWMLoadWinnet16,
HookWMFreeWinnet16,
HookWMGetProcAddressByName,
HookWMGetProcAddressByOrdinal };
DWORD NPSERVICE HookHookMPR ( PMPRCALLS pMPRCalls )
{
return ((PF_NPSHookMPR)(MPRCalls.pfNPSHookMPR))(pMPRCalls);
}
DWORD NPSERVICE HookUnHookMPR ( PF_NPSHookMPR pfReqNPSHookMPR,
PMPRCALLS pReqMPRCalls )
{
if (pfReqNPSHookMPR == HookHookMPR) {
// The unhook request has reached the hooker that issued
// the NPSUnHookMe call (us).
// In other words we are now sucessfully unhooked
// and may do our unhooking cleanup.
// In particular, we can release our tables that
// manage LoadLibrary/GetProcAddress.
// Note that this code may be executing on a different
// thread to the NPSUnHookMe call which may have returned
// a while ago.
return WN_SUCCESS;
}
else {
// Another hooker has requested to unhook by calling
// NPSUnHookMe which causes us to be called here.
// Pass the request on to the MPR service NPSUnHookMPR to
// process the request, giving it our MPRCALLS
// data structure so that it can figure out if
// we are the right hooker to update and otherwise
// MPR will pass the request on to the next hooker.
return NPSUnHookMPR ( pfReqNPSHookMPR,
pReqMPRCalls,
(PMPRCALLS)&MPRCalls );
}
}
HINSTANCE HookLoadLibrary(
LPCTSTR lpszLibFile
)
{
return MPRCalls.pfLoadLibrary(lpszLibFile);
}
BOOL HookFreeLibrary(
HMODULE hLibModule
)
{
return MPRCalls.pfFreeLibrary(hLibModule);
}
FARPROC HookGetProcAddress(
HMODULE hModule,
LPCSTR lpszProc
)
{
return MPRCalls.pfGetProcAddress(hModule, lpszProc);
}
HANDLE16 HookWMLoadWinnet16(
LPCTSTR lpszLibFile
)
{
return MPRCalls.pfLoadLibrary16(lpszLibFile);
}
VOID HookWMFreeWinnet16(
HANDLE16 hLibModule
)
{
MPRCalls.pfFreeLibrary16(hLibModule);
}
DWORD WINAPI HookWMGetProcAddressByName(
LPCSTR lpszProc,
HANDLE16 hModule
)
{
return MPRCalls.pfGetProcAddressByName16(lpszProc, hModule);
}
DWORD WINAPI HookWMGetProcAddressByOrdinal(
WORD wOrdinal,
HANDLE16 hModule
)
{
return MPRCalls.pfGetProcAddressByOrdinal16(wOrdinal, hModule);
}
void KickMPR(void)
{
if (NPSHookMPR((PMPRCALLS)&MPRCalls) == WN_SUCCESS) {
NPSUnHookMe(HookHookMPR, (PMPRCALLS)&MPRCalls);
}
}
/***** End MPR hooking code *****/
/***** Begin code to delay-load the real net provider DLL *****/
HMODULE hmodRealNP = NULL;
PF_NPGetCaps pfnNPGetCaps = NULL;
PF_NPGetUniversalName pfnNPGetUniversalName = NULL;
PF_NPGetUser pfnNPGetUser = NULL;
PF_NPValidLocalDevice pfnNPValidLocalDevice = NULL;
PF_NPAddConnection pfnNPAddConnection = NULL;
PF_NPCancelConnection pfnNPCancelConnection = NULL;
PF_NPGetConnection pfnNPGetConnection = NULL;
PF_NPGetConnectionPerformance pfnNPGetConnectionPerformance = NULL;
PF_NPFormatNetworkName pfnNPFormatNetworkName = NULL;
PF_NPOpenEnum pfnNPOpenEnum = NULL;
PF_NPEnumResource pfnNPEnumResource = NULL;
PF_NPCloseEnum pfnNPCloseEnum = NULL;
PF_NPGetResourceParent pfnNPGetResourceParent = NULL;
PF_NPGetResourceInformation pfnNPGetResourceInformation = NULL;
PF_NPLogon pfnNPLogon = NULL;
PF_NPLogoff pfnNPLogoff = NULL;
PF_NPGetHomeDirectory pfnNPGetHomeDirectory = NULL;
PF_NPGetPolicyPath pfnNPGetPolicyPath = NULL;
struct {
UINT nOrd;
FARPROC *ppfn;
} aProcs[] = {
{ ORD_GETCAPS, (FARPROC *)&pfnNPGetCaps },
{ ORD_GETUNIVERSALNAME, (FARPROC *)&pfnNPGetUniversalName },
{ ORD_GETUSER, (FARPROC *)&pfnNPGetUser },
{ ORD_VALIDDEVICE, (FARPROC *)&pfnNPValidLocalDevice },
{ ORD_ADDCONNECTION, (FARPROC *)&pfnNPAddConnection },
{ ORD_CANCELCONNECTION, (FARPROC *)&pfnNPCancelConnection },
{ ORD_GETCONNECTIONS, (FARPROC *)&pfnNPGetConnection },
{ ORD_GETCONNPERFORMANCE, (FARPROC *)&pfnNPGetConnectionPerformance },
{ ORD_FORMATNETWORKNAME, (FARPROC *)&pfnNPFormatNetworkName },
{ ORD_OPENENUM, (FARPROC *)&pfnNPOpenEnum },
{ ORD_ENUMRESOURCE, (FARPROC *)&pfnNPEnumResource },
{ ORD_CLOSEENUM, (FARPROC *)&pfnNPCloseEnum },
{ ORD_GETRESOURCEPARENT, (FARPROC *)&pfnNPGetResourceParent },
{ ORD_GETRESOURCEINFORMATION, (FARPROC *)&pfnNPGetResourceInformation },
{ ORD_LOGON, (FARPROC *)&pfnNPLogon },
{ ORD_LOGOFF, (FARPROC *)&pfnNPLogoff },
{ ORD_GETHOMEDIRECTORY, (FARPROC *)&pfnNPGetHomeDirectory },
{ ORD_GETPOLICYPATH, (FARPROC *)&pfnNPGetPolicyPath },
};
void LoadRealNP(void)
{
ENTERCRITICAL
if (::hmodRealNP == NULL) {
char szDLLName[MAX_PATH];
szDLLName[0] = '\0';
HKEY hkeySection;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\NPSTUB\\NetworkProvider",
0, KEY_QUERY_VALUE, &hkeySection) == ERROR_SUCCESS) {
DWORD dwType;
DWORD cbData = sizeof(szDLLName);
RegQueryValueEx(hkeySection, "RealDLL", NULL, &dwType, (LPBYTE)szDLLName, &cbData);
RegCloseKey(hkeySection);
}
if (szDLLName[0] == '\0')
lstrcpy(szDLLName, "mslocusr.dll");
::hmodRealNP = LoadLibrary(szDLLName);
if (::hmodRealNP != NULL) {
for (UINT i=0; i<ARRAYSIZE(::aProcs); i++) {
*(aProcs[i].ppfn) = GetProcAddress(::hmodRealNP, (LPCSTR)aProcs[i].nOrd);
}
}
}
LEAVECRITICAL
}
void UnloadRealNP(void)
{
ENTERCRITICAL
{
if (cCallsInProgress > 0) {
fShouldUnload = TRUE;
}
else {
for (UINT i=0; i<ARRAYSIZE(::aProcs); i++) {
*(aProcs[i].ppfn) = NULL;
}
FreeLibrary(hmodRealNP);
hmodRealNP = NULL;
fShouldUnload = FALSE;
KickMPR();
}
}
LEAVECRITICAL
}
LRESULT MonitorWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_NPSTUB_LOADDLL:
LoadRealNP();
KickMPR();
break;
case WM_NPSTUB_UNLOADDLL:
UnloadRealNP();
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void _ProcessAttach()
{
//
// All the per-instance initialization code should come here.
//
::DisableThreadLibraryCalls(::hInstance);
InitializeCriticalSection(&::critsec);
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = MonitorWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ::hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = szNPSTUBClassName;
::aClass = RegisterClass(&wc);
if (::aClass != NULL) {
::hwndMonitor = CreateWindow(szNPSTUBClassName, "",
WS_POPUP | WS_DISABLED,
0, 0, 0, 0,
NULL, NULL,
::hInstance, NULL);
}
LoadRealNP();
}
void _ProcessDetach()
{
if (::hwndMonitor != NULL)
DestroyWindow(::hwndMonitor);
if (::aClass != NULL)
UnregisterClass((LPSTR)(WORD)::aClass, ::hInstance);
DeleteCriticalSection(&::critsec);
}
extern "C" STDAPI_(BOOL) DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID reserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
::hInstance = hInstDll;
_ProcessAttach();
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
_ProcessDetach();
}
return TRUE;
}
void EnterSPI(void)
{
ENTERCRITICAL
{
::cCallsInProgress++;
}
LEAVECRITICAL
}
void LeaveSPI(void)
{
ENTERCRITICAL
{
::cCallsInProgress--;
if (::fShouldUnload && !::cCallsInProgress)
PostMessage(::hwndMonitor, WM_NPSTUB_UNLOADDLL, 0, 0);
}
LEAVECRITICAL
}
#define CALLNP(name,err,params) \
{ \
if (pfn##name == NULL) \
return err; \
DWORD dwRet = err; \
EnterSPI(); \
if (pfn##name != NULL) \
dwRet = (*pfn##name)params; \
LeaveSPI(); \
return dwRet; \
} //last line doesn't need a backslash
SPIENTRY NPGetCaps(
DWORD nIndex
)
{
CALLNP(NPGetCaps,0,(nIndex));
}
SPIENTRY NPGetUniversalName(
LPTSTR lpLocalPath,
DWORD dwInfoLevel,
LPVOID lpBuffer,
LPDWORD lpBufferSize
)
{
CALLNP(NPGetUniversalName,WN_NOT_SUPPORTED,
(lpLocalPath,dwInfoLevel,lpBuffer,lpBufferSize));
}
SPIENTRY NPGetUser(
LPTSTR lpName,
LPTSTR lpAuthenticationID,
LPDWORD lpBufferSize
)
{
CALLNP(NPGetUser,WN_NOT_SUPPORTED,
(lpName,lpAuthenticationID,lpBufferSize));
}
SPIENTRY NPValidLocalDevice(
DWORD dwType,
DWORD dwNumber
)
{
CALLNP(NPValidLocalDevice,WN_NOT_SUPPORTED,(dwType,dwNumber));
}
SPIENTRY NPAddConnection(
HWND hwndOwner,
LPNETRESOURCE lpNetResource,
LPTSTR lpPassword,
LPTSTR lpUserID,
DWORD dwFlags,
LPTSTR lpAccessName,
LPDWORD lpBufferSize,
LPDWORD lpResult
)
{
CALLNP(NPAddConnection,WN_NOT_SUPPORTED,
(hwndOwner,lpNetResource,lpPassword,lpUserID,dwFlags,lpAccessName,lpBufferSize,lpResult));
}
SPIENTRY NPCancelConnection(
LPTSTR lpName,
BOOL fForce,
DWORD dwFlags
)
{
CALLNP(NPCancelConnection,WN_NOT_SUPPORTED,
(lpName,fForce,dwFlags));
}
SPIENTRY NPGetConnection(
LPTSTR lpLocalName,
LPTSTR lpRemoteName,
LPDWORD lpBufferSize
)
{
CALLNP(NPGetConnection,WN_NOT_SUPPORTED,
(lpLocalName,lpRemoteName,lpBufferSize));
}
SPIENTRY NPGetConnectionPerformance(
LPTSTR lpRemoteName,
LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct
)
{
CALLNP(NPGetConnectionPerformance,WN_NOT_SUPPORTED,
(lpRemoteName,lpNetConnectInfoStruct));
}
SPIENTRY NPFormatNetworkName(
LPTSTR lpRemoteName,
LPTSTR lpFormattedName,
LPDWORD lpnLength,
DWORD dwFlags,
DWORD dwAveCharPerLine
)
{
CALLNP(NPFormatNetworkName,WN_NOT_SUPPORTED,
(lpRemoteName,lpFormattedName,lpnLength,dwFlags,dwAveCharPerLine));
}
SPIENTRY NPOpenEnum(
DWORD dwScope,
DWORD dwType,
DWORD dwUsage,
LPNETRESOURCE lpNetResource,
LPHANDLE lphEnum
)
{
CALLNP(NPOpenEnum,WN_NOT_SUPPORTED,
(dwScope,dwType,dwUsage,lpNetResource,lphEnum));
}
SPIENTRY NPEnumResource(
HANDLE hEnum,
LPDWORD lpcCount,
LPVOID lpBuffer,
DWORD cbBuffer,
LPDWORD lpcbFree
)
{
CALLNP(NPEnumResource,WN_NOT_SUPPORTED,
(hEnum,lpcCount,lpBuffer,cbBuffer,lpcbFree));
}
SPIENTRY NPCloseEnum(
HANDLE hEnum
)
{
CALLNP(NPCloseEnum,WN_NOT_SUPPORTED,
(hEnum));
}
SPIENTRY NPGetResourceParent(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD cbBuffer
)
{
CALLNP(NPGetResourceParent,WN_NOT_SUPPORTED,
(lpNetResource,lpBuffer,cbBuffer));
}
SPIENTRY NPGetResourceInformation(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD cbBuffer,
LPSTR *lplpSystem
)
{
CALLNP(NPGetResourceInformation,WN_NOT_SUPPORTED,
(lpNetResource,lpBuffer,cbBuffer,lplpSystem));
}
SPIENTRY NPLogon(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo,
LPLOGONINFO lpPreviousAuthentInfo,
LPTSTR lpLogonScript,
DWORD dwBufferSize,
DWORD dwFlags
)
{
CALLNP(NPLogon,WN_NOT_SUPPORTED,
(hwndOwner,lpAuthentInfo,lpPreviousAuthentInfo,lpLogonScript,dwBufferSize,dwFlags));
}
SPIENTRY NPLogoff(
HWND hwndOwner,
LPLOGONINFO lpAuthentInfo,
DWORD dwReason
)
{
CALLNP(NPLogoff,WN_NOT_SUPPORTED,
(hwndOwner,lpAuthentInfo,dwReason));
}
SPIENTRY NPGetHomeDirectory(
LPTSTR lpDirectory,
LPDWORD lpBufferSize
)
{
CALLNP(NPGetHomeDirectory,WN_NOT_SUPPORTED,
(lpDirectory,lpBufferSize));
}
SPIENTRY NPGetPolicyPath(
LPTSTR lpPath,
LPDWORD lpBufferSize,
DWORD dwFlags
)
{
CALLNP(NPGetPolicyPath,WN_NOT_SUPPORTED,
(lpPath,lpBufferSize,dwFlags));
}