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.
1408 lines
34 KiB
1408 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smbrdr.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the functios to load and unload the
|
|
smb monolithic minirdr. Also explicit start/stop control is
|
|
provided
|
|
|
|
This module also populates the registry entries for the
|
|
driver, and the network provider.
|
|
|
|
--*/
|
|
//#ifndef UNICODE
|
|
//#define UNICODE
|
|
//#endif
|
|
|
|
#include <windows.h>
|
|
#include <devioctl.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "srfunc.h"
|
|
|
|
|
|
#ifdef DBG
|
|
#define DbgP(_x_) DbgPrint _x_
|
|
#else
|
|
#define DbgP(_x_)
|
|
#endif
|
|
|
|
ULONG _cdecl DbgPrint( LPTSTR Format, ... );
|
|
|
|
#define TRACE_TAG L"SMBRDR: "
|
|
|
|
|
|
|
|
TCHAR* SmbMrxDriverName = TEXT("SmbMRx");
|
|
|
|
|
|
// load action states
|
|
|
|
ULONG_PTR LoadActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_LOADING,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE
|
|
};
|
|
|
|
// unload action states
|
|
ULONG_PTR UnloadActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_UNLOADING,
|
|
RDR_UNLOADING,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE
|
|
};
|
|
|
|
// Start action states
|
|
ULONG_PTR StartActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_STARTING,
|
|
RDR_STARTING,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE
|
|
};
|
|
|
|
// Stop action states
|
|
ULONG_PTR StopActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_STOPPING
|
|
};
|
|
|
|
ULONG_PTR TransitionActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_UNLOADED,
|
|
RDR_LOADED,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_STOPPED,
|
|
RDR_STARTED,
|
|
RDR_NULL_STATE
|
|
};
|
|
|
|
ULONG_PTR ErrorActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_LOADED,
|
|
RDR_UNLOADED,
|
|
RDR_NULL_STATE,
|
|
RDR_NULL_STATE,
|
|
RDR_STARTED,
|
|
RDR_STOPPED,
|
|
RDR_NULL_STATE
|
|
};
|
|
|
|
ULONG_PTR NoneActionStates[] =
|
|
{
|
|
RDR_NULL_STATE,
|
|
RDR_UNLOADED,
|
|
RDR_UNLOADING,
|
|
RDR_LOADING,
|
|
RDR_LOADED,
|
|
RDR_STOPPED,
|
|
RDR_STOPPING,
|
|
RDR_STARTING,
|
|
RDR_STARTED
|
|
};
|
|
|
|
|
|
ULONG_PTR *ActionsStatesArray[] =
|
|
{
|
|
LoadActionStates,
|
|
UnloadActionStates,
|
|
StartActionStates,
|
|
StopActionStates,
|
|
TransitionActionStates,
|
|
ErrorActionStates,
|
|
NoneActionStates
|
|
};
|
|
|
|
ACTIONVECTOR ActionProcs[] =
|
|
{
|
|
RdrLoad,
|
|
RdrUnload,
|
|
RdrStart,
|
|
RdrStop,
|
|
RdrDoNothing,
|
|
RdrDoNothing,
|
|
RdrDoNothing
|
|
};
|
|
|
|
|
|
typedef enum _INSTALLCHECKS
|
|
{
|
|
installcheck_start,
|
|
installcheck_driverfile,
|
|
installcheck_providerfile,
|
|
installcheck_serviceentry,
|
|
installcheck_providerorder,
|
|
installcheck_stop,
|
|
installcheck_done
|
|
};
|
|
|
|
|
|
ULONG_PTR RdrInstallCheck( void )
|
|
{
|
|
TCHAR tszTestPath[_MAX_PATH];
|
|
ULONG_PTR teststep;
|
|
ULONG len = 0;
|
|
ULONG_PTR tc = SETUP_COMPLETE;
|
|
HANDLE th;
|
|
|
|
for ( teststep = installcheck_start; teststep < installcheck_done; teststep++ )
|
|
{
|
|
switch ( teststep )
|
|
{
|
|
case installcheck_start:
|
|
{
|
|
len = GetWindowsDirectory( tszTestPath, _MAX_PATH );
|
|
}
|
|
break;
|
|
|
|
case installcheck_driverfile:
|
|
{
|
|
lstrcpyn( &tszTestPath[len], DRIVER_FILE_PATH, _MAX_PATH - len );
|
|
th = CreateFile( tszTestPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL );
|
|
if ( th == INVALID_HANDLE_VALUE )
|
|
{
|
|
tc = SETUP_MISSING_FILE;
|
|
teststep = installcheck_stop;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle( th );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case installcheck_providerfile:
|
|
{
|
|
lstrcpyn( &tszTestPath[len], PROVIDER_FILE_PATH, _MAX_PATH - len );
|
|
th = CreateFile( tszTestPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL );
|
|
if ( th == INVALID_HANDLE_VALUE )
|
|
{
|
|
tc = SETUP_MISSING_FILE;
|
|
teststep = installcheck_stop;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle( th );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case installcheck_serviceentry:
|
|
{
|
|
HKEY hTestKey;
|
|
|
|
if ( OpenKey( RDRSERVICE_KEY, &hTestKey ) )
|
|
{
|
|
RegCloseKey( hTestKey );
|
|
}
|
|
else
|
|
{
|
|
tc = SETUP_INCOMPLETE;
|
|
teststep = installcheck_stop;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case installcheck_providerorder:
|
|
{
|
|
LPTSTR pOrder;
|
|
|
|
RdrGetProviderOrderString( &pOrder );
|
|
if ( pOrder )
|
|
{
|
|
if ( !RdrFindProviderInOrder( pOrder, PROVIDER_NAME ) )
|
|
{
|
|
tc = SETUP_INCOMPLETE;
|
|
teststep = installcheck_stop;
|
|
}
|
|
free( pOrder );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case installcheck_stop:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return tc;
|
|
}
|
|
|
|
BOOL RdrCompleteSetup( void )
|
|
{
|
|
return RdrSetupServiceEntry( ) && RdrSetupProviderOrder( );
|
|
}
|
|
|
|
// These handles are retained
|
|
|
|
HANDLE hSharedMemory;
|
|
HANDLE hMutex;
|
|
|
|
|
|
BOOL RdrStart(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts the SMB sample mini redirector.
|
|
|
|
Notes:
|
|
|
|
The start is distinguished from Load. During this phase the appropriate FSCTL
|
|
is issued and the shared memory/mutex data structures required for the Network
|
|
provider DLL are initialized.
|
|
|
|
--*/
|
|
{
|
|
|
|
HANDLE DeviceHandle; // The mini rdr device handle
|
|
DWORD BytesRet;
|
|
BOOL started = FALSE;
|
|
|
|
// Grab a handle to the redirector device object
|
|
|
|
DbgP((TEXT("Opening Rdr Device Object for Start Ioctl\n")));
|
|
DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
DbgP((TEXT("returned from rdr device open\n")));
|
|
|
|
if ( DeviceHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
DbgP(( TEXT("Issueing Rdr Start Ioctl\n") ));
|
|
started = DeviceIoControl( DeviceHandle,
|
|
IOCTL_SMBMRX_START,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&BytesRet,
|
|
NULL );
|
|
|
|
// Create a section of shared memory to serve as the connection database
|
|
if ( started )
|
|
{
|
|
DWORD Status;
|
|
|
|
hSharedMemory = CreateFileMapping( INVALID_HANDLE_VALUE,
|
|
NULL,
|
|
PAGE_READWRITE,
|
|
0,
|
|
sizeof(SMBMRXNP_SHARED_MEMORY),
|
|
SMBMRXNP_SHARED_MEMORY_NAME);
|
|
|
|
if (hSharedMemory == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
|
|
DbgP((TEXT("SMB MRx Net Provider shared memory Creation status %lx\n"),Status));
|
|
}
|
|
else
|
|
{
|
|
PSMBMRXNP_SHARED_MEMORY pSharedMemory;
|
|
|
|
pSharedMemory = MapViewOfFile(hSharedMemory, FILE_MAP_WRITE, 0, 0, 0);
|
|
|
|
if (pSharedMemory != NULL)
|
|
{
|
|
pSharedMemory->HighestIndexInUse = -1;
|
|
pSharedMemory->NumberOfResourcesInUse = 0;
|
|
}
|
|
|
|
UnmapViewOfFile(pSharedMemory);
|
|
}
|
|
|
|
hMutex = CreateMutex( NULL,
|
|
FALSE,
|
|
SMBMRXNP_MUTEX_NAME);
|
|
|
|
if (hMutex == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
DbgP(( TEXT("SMB MRx Net Provider Mutex Creation status %lx\n"), Status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgP(( TEXT("The DeviceIoctl for Starting Redirector returned %lx\n"), GetLastError() ));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DbgP(( TEXT("The CreateFile for opening device failed with error 0x%lx\n"), GetLastError() ));
|
|
DbgP(( TEXT("Device is %s\n"),DD_SMBMRX_USERMODE_DEV_NAME ));
|
|
}
|
|
|
|
//DbgP((TEXT("SMB MRx sample mini redirector start status %lx\n"),ntstatus));
|
|
|
|
CloseHandle(DeviceHandle);
|
|
|
|
return started;
|
|
|
|
|
|
}
|
|
|
|
BOOL RdrStop( void )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops the SMB sample mini redirector.
|
|
|
|
Notes:
|
|
|
|
The stop is distinguished from unload. During this phase the appropriate FSCTL
|
|
is issued and the shared memory/mutex data structures required for the Network
|
|
provider DLL are torn down.
|
|
|
|
--*/
|
|
{
|
|
HANDLE DeviceHandle; // The mini rdr device handle
|
|
DWORD BytesRet;
|
|
BOOL stopped = FALSE;
|
|
|
|
// Grab a handle to the redirector device object
|
|
|
|
DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
DbgP((TEXT("Doing Stop DeviceIoControl\n")));
|
|
if ( DeviceHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
stopped = DeviceIoControl( DeviceHandle,
|
|
IOCTL_SMBMRX_STOP,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&BytesRet,
|
|
NULL );
|
|
|
|
CloseHandle( DeviceHandle );
|
|
}
|
|
else
|
|
{
|
|
DbgP(( TEXT("The CreateFile for opening device failed\n") ));
|
|
}
|
|
|
|
CloseHandle(hMutex);
|
|
CloseHandle(hSharedMemory);
|
|
|
|
// DbgP(( TEXT("SMB MRx sample mini redirector start status %lx\n"),ntstatus ));
|
|
|
|
return stopped;
|
|
}
|
|
|
|
|
|
BOOL RdrLoad( void )
|
|
{
|
|
SC_HANDLE sch, service;
|
|
BOOL loaded = FALSE;
|
|
|
|
DbgP((TEXT("Loading SMB sample minirdr.......\n")));
|
|
|
|
sch = OpenSCManager( NULL, NULL, GENERIC_EXECUTE );
|
|
if ( sch )
|
|
{
|
|
service = OpenService( sch, RDRSERVICE, GENERIC_EXECUTE );
|
|
if ( service )
|
|
{
|
|
loaded = StartService( service, 0, NULL );
|
|
CloseServiceHandle( service );
|
|
}
|
|
CloseServiceHandle( sch );
|
|
}
|
|
|
|
return loaded;
|
|
}
|
|
|
|
|
|
BOOL RdrUnload( void )
|
|
{
|
|
SC_HANDLE sch, service;
|
|
BOOL unloaded = FALSE;
|
|
|
|
DbgP((TEXT("Unloading SMB sample minirdr.......\n")));
|
|
|
|
sch = OpenSCManager( NULL, NULL, GENERIC_EXECUTE );
|
|
if ( sch )
|
|
{
|
|
service = OpenService( sch, RDRSERVICE, GENERIC_EXECUTE );
|
|
if ( service )
|
|
{
|
|
SERVICE_STATUS ss;
|
|
|
|
unloaded = ControlService( service, SERVICE_CONTROL_STOP, &ss );
|
|
CloseServiceHandle( service );
|
|
}
|
|
CloseServiceHandle( sch );
|
|
}
|
|
|
|
return unloaded;
|
|
}
|
|
|
|
|
|
BOOL RdrDoNothing( void )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL RdrDoAction( ULONG_PTR action )
|
|
{
|
|
return (*ActionProcs[action])( );
|
|
}
|
|
|
|
|
|
ULONG_PTR RdrGetInitialState(void)
|
|
{
|
|
ULONG_PTR state = RDR_UNLOADED;
|
|
SC_HANDLE sch, service;
|
|
|
|
sch = OpenSCManager( NULL, NULL, GENERIC_READ );
|
|
if ( sch )
|
|
{
|
|
service = OpenService( sch, RDRSERVICE, GENERIC_READ );
|
|
if ( service )
|
|
{
|
|
SERVICE_STATUS ss;
|
|
|
|
if ( QueryServiceStatus( service, &ss ) )
|
|
{
|
|
switch ( ss.dwCurrentState )
|
|
{
|
|
case SERVICE_STOPPED:
|
|
state = RDR_UNLOADED;
|
|
break;
|
|
case SERVICE_START_PENDING:
|
|
state = RDR_LOADING;
|
|
break;
|
|
case SERVICE_STOP_PENDING:
|
|
state = RDR_UNLOADING;
|
|
break;
|
|
case SERVICE_RUNNING:
|
|
state = RDR_LOADED;
|
|
break;
|
|
case SERVICE_CONTINUE_PENDING:
|
|
case SERVICE_PAUSE_PENDING:
|
|
case SERVICE_PAUSED:
|
|
default:
|
|
state = RDR_UNLOADED;
|
|
break;
|
|
|
|
}
|
|
#if 0 //just check for load/unload state for now
|
|
|
|
// go check the start/stop state
|
|
if ( state == RDR_LOADED )
|
|
{
|
|
BOOL IsOk;
|
|
HANDLE DeviceHandle;
|
|
DWORD BytesRet;
|
|
ULONG_PTR RdrStateValue;
|
|
|
|
DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if ( DeviceHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
DbgP((TEXT("Doing Get State DeviceIoControl\n")));
|
|
IsOk = DeviceIoControl( DeviceHandle,
|
|
IOCTL_SMBMRX_GETSTATE,
|
|
NULL,
|
|
0,
|
|
&RdrStateValue,
|
|
sizeof(ULONG),
|
|
&BytesRet,
|
|
NULL );
|
|
CloseHandle( DeviceHandle );
|
|
}
|
|
if ( IsOk )
|
|
{
|
|
state = RdrStateValue;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
CloseServiceHandle( service );
|
|
}
|
|
CloseServiceHandle( sch );
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
ULONG_PTR RdrGetNextState( ULONG_PTR Action, ULONG_PTR CurrentState )
|
|
{
|
|
return ActionsStatesArray[Action][CurrentState];
|
|
}
|
|
|
|
|
|
REGENTRY LinkageKeyValues[] =
|
|
{
|
|
{ TEXT("Bind"), REG_MULTI_SZ, 0, 0 },
|
|
{ TEXT("Export"), REG_MULTI_SZ, 0, 0 },
|
|
{ TEXT("Route"), REG_MULTI_SZ, 0, 0 }
|
|
};
|
|
|
|
REGENTRY LinkageDisabledKeyValues[] =
|
|
{
|
|
{ TEXT("Bind"), REG_MULTI_SZ, 0, 0 },
|
|
{ TEXT("Export"), REG_MULTI_SZ, 0, 0 },
|
|
{ TEXT("Route"), REG_MULTI_SZ, 0, 0 }
|
|
};
|
|
|
|
|
|
REGENTRY NetworkProviderKeyValues[] =
|
|
{
|
|
{
|
|
TEXT("Devicename"),
|
|
REG_SZ,
|
|
sizeof(SMBMRX_DEVICE_NAME),
|
|
SMBMRX_DEVICE_NAME
|
|
},
|
|
{
|
|
TEXT("ProviderPath"),
|
|
REG_EXPAND_SZ,
|
|
sizeof(PROVIDER_PATH),
|
|
PROVIDER_PATH
|
|
},
|
|
{
|
|
TEXT("Name"),
|
|
REG_SZ,
|
|
sizeof(SMBMRX_PROVIDER_NAME),
|
|
SMBMRX_PROVIDER_NAME
|
|
}
|
|
};
|
|
|
|
|
|
REGENTRY ProviderOrderKeyValues[] =
|
|
{
|
|
{ TEXT("ProviderOrder"), REG_SZ, 0, 0 }
|
|
};
|
|
|
|
BOOL RdrSetupServiceEntry( void )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the registry entries for the smbmrx
|
|
minirdr. This only needs to be done once.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
HKEY hCurrentKey;
|
|
SC_HANDLE sch, service;
|
|
BOOL success = TRUE;
|
|
|
|
DbgP(( TEXT( "Setting up ") RDRSERVICE TEXT(" registry Entries\n" ) ));
|
|
sch = OpenSCManager( NULL, NULL, GENERIC_WRITE );
|
|
if ( sch )
|
|
{
|
|
service = CreateService( sch,
|
|
RDRSERVICE,
|
|
RDRSERVICE,
|
|
SERVICE_ALL_ACCESS,
|
|
SERVICE_FILE_SYSTEM_DRIVER,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
TEXT("System32\\DRIVERS\\") RDRSERVICE TEXT(".sys"),
|
|
TEXT("Network"),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
|
|
if ( service )
|
|
{
|
|
CloseServiceHandle( service );
|
|
}
|
|
else if ( GetLastError( ) != ERROR_SERVICE_EXISTS )
|
|
{
|
|
success = FALSE;
|
|
}
|
|
CloseServiceHandle( sch );
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
|
|
|
|
// Read the linkage values associated with the Lanman workstation service.
|
|
// This contains all the transports and the order in which they need to be used
|
|
if ( success && OpenKey( WKSSERVICE_KEY TEXT("\\Linkage"), &hCurrentKey ) )
|
|
{
|
|
ULONG i;
|
|
|
|
ReadRegistryKeyValues( hCurrentKey,
|
|
sizeof(LinkageKeyValues) / sizeof(REGENTRY),
|
|
LinkageKeyValues);
|
|
RegCloseKey(hCurrentKey);
|
|
// Update the SMB MRx linkage values
|
|
if ( CreateKey( RDRSERVICE_KEY TEXT("\\Linkage"), &hCurrentKey ) )
|
|
{
|
|
WriteRegistryKeyValues( hCurrentKey,
|
|
sizeof(LinkageKeyValues) / sizeof(REGENTRY),
|
|
LinkageKeyValues);
|
|
RegCloseKey(hCurrentKey);
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
for ( i = 0; i < ( sizeof(LinkageKeyValues) / sizeof(REGENTRY) ); i++ )
|
|
{
|
|
if ( LinkageKeyValues[i].pvValue )
|
|
{
|
|
free( LinkageKeyValues[i].pvValue );
|
|
LinkageKeyValues[i].pvValue = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
|
|
//if ( OpenKey( WKSSERVICE_KEY TEXT("\\Linkage\\Disabled",&hCurrentKey))
|
|
//{
|
|
// ReadRegistryKeyValues( hCurrentKey,
|
|
// sizeof(LinkageDisabledKeyValues) / sizeof(REGENTRY),
|
|
// LinkageDisabledKeyValues);
|
|
// RegCloseKey(hCurrentKey);
|
|
//}
|
|
//else
|
|
//{
|
|
// DbgP(( TEXT("Error Opening Key %s Status %d\n"),WKSSERVICE_KEY TEXT("\\Linkage\\Disabled"),GetLastError() ));
|
|
// return;
|
|
//}
|
|
|
|
// Update the SMB MRx linkage disabled values
|
|
//if ( CreateKey( RDRSERVICE_KEY TEXT("\\Linkage\\Disabled") ,&hCurrentKey))
|
|
//{
|
|
// WriteRegistryKeyValues( hCurrentKey,
|
|
// sizeof(LinkageDisabledKeyValues)/sizeof(REGENTRY),
|
|
// LinkageDisabledKeyValues );
|
|
// RegCloseKey(hCurrentKey);
|
|
//}
|
|
//else
|
|
//{
|
|
// DbgP(( TEXT("Error Creating Key %s Status %d\n"),RDRSERVICE_KEY TEXT("\\linkage\\disabled",GetLastError() ));
|
|
// return;
|
|
//}
|
|
|
|
// Update the SMBmrx network provider section
|
|
if ( success && CreateKey( RDRSERVICE_KEY TEXT("\\NetworkProvider"), &hCurrentKey ) )
|
|
{
|
|
WriteRegistryKeyValues( hCurrentKey,
|
|
sizeof(NetworkProviderKeyValues)/sizeof(REGENTRY),
|
|
NetworkProviderKeyValues);
|
|
RegCloseKey(hCurrentKey);
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
|
|
|
|
if ( success && CreateKey( RDRSERVICE_KEY TEXT("\\Parameters"), &hCurrentKey ) )
|
|
{
|
|
RegCloseKey( hCurrentKey );
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
BOOL RdrSetupProviderOrder( void )
|
|
{
|
|
LPTSTR pOrderString = NULL;
|
|
ULONG_PTR len;
|
|
BOOL success = TRUE;
|
|
|
|
len = RdrGetProviderOrderString( &pOrderString ) * sizeof(TCHAR);
|
|
if ( len > 0 && pOrderString )
|
|
{
|
|
if ( !RdrFindProviderInOrder( pOrderString, PROVIDER_NAME ) )
|
|
{
|
|
LPTSTR pNewOrderString;
|
|
|
|
len += sizeof( PROVIDER_NAME ) + (2 * sizeof(TCHAR)); // add 2 for comma delimeter and null
|
|
pNewOrderString = malloc( len );
|
|
if ( pNewOrderString )
|
|
{
|
|
lstrcpy( pNewOrderString, pOrderString );
|
|
lstrcat( pNewOrderString, TEXT(",") );
|
|
lstrcat( pNewOrderString, PROVIDER_NAME );
|
|
success = RdrSetProviderOrderString( pNewOrderString );
|
|
free( pNewOrderString );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
success = RdrSetProviderOrderString( PROVIDER_NAME );
|
|
}
|
|
if ( pOrderString )
|
|
{
|
|
free( pOrderString );
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
ULONG_PTR RdrGetProviderOrderString( LPTSTR *OrderString )
|
|
{
|
|
HKEY hOrderKey;
|
|
ULONG_PTR len = 0;
|
|
|
|
if ( OpenKey( PROVIDER_ORDER_KEY, &hOrderKey ) )
|
|
{
|
|
ReadRegistryKeyValues( hOrderKey,
|
|
sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY),
|
|
ProviderOrderKeyValues);
|
|
|
|
RegCloseKey(hOrderKey);
|
|
len = ProviderOrderKeyValues[0].dwLength / sizeof( TCHAR ) - 1;
|
|
*OrderString = (LPTSTR) ProviderOrderKeyValues[0].pvValue;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
BOOL RdrSetProviderOrderString( LPTSTR OrderString )
|
|
{
|
|
HKEY hOrderKey;
|
|
ULONG len = 0;
|
|
BOOL rc = FALSE;
|
|
|
|
if ( CreateKey( PROVIDER_ORDER_KEY, &hOrderKey ) )
|
|
{
|
|
ProviderOrderKeyValues[0].dwLength = ( lstrlen( OrderString ) + 1 ) * sizeof( TCHAR );
|
|
ProviderOrderKeyValues[0].pvValue = OrderString;
|
|
WriteRegistryKeyValues( hOrderKey,
|
|
sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY),
|
|
ProviderOrderKeyValues);
|
|
RegCloseKey(hOrderKey);
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL RdrFindProviderInOrder( LPTSTR OrderString, LPTSTR Provider )
|
|
{
|
|
LPTSTR pCompare;
|
|
BOOL match = FALSE;
|
|
|
|
if ( OrderString && Provider && *Provider )
|
|
{
|
|
pCompare = Provider;
|
|
|
|
while ( *OrderString )
|
|
{
|
|
if ( toupper(*OrderString++) != toupper(*pCompare++) )
|
|
{
|
|
pCompare = Provider;
|
|
}
|
|
if ( *pCompare == TEXT('\0') )
|
|
{
|
|
if ( ( *OrderString == TEXT(',') ) || ( *OrderString == TEXT('\0') ) )
|
|
{
|
|
match = TRUE;
|
|
break;
|
|
}
|
|
else // hmm, it's a substring of another provider name
|
|
{
|
|
while ( ( *OrderString != TEXT(',') ) && ( *OrderString != TEXT('\0') ) )
|
|
{
|
|
OrderString++;
|
|
}
|
|
pCompare = Provider;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
ReadRegistryKeyValues(
|
|
HKEY hCurrentKey,
|
|
DWORD NumberOfValues,
|
|
PREGENTRY pValues)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a bunch of values associated with a given key.
|
|
|
|
Arguments:
|
|
|
|
hCurrentKey - the key
|
|
|
|
NumberOfValues - the number of values
|
|
|
|
pValues - the array of values
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Iterate through table reading the values along the way
|
|
//
|
|
|
|
DWORD i;
|
|
|
|
for (i = 0; i < NumberOfValues; i++)
|
|
{
|
|
DWORD dwType;
|
|
LPTSTR pszKey;
|
|
|
|
dwType = pValues[i].dwType;
|
|
pszKey = pValues[i].pszKey;
|
|
|
|
switch (dwType)
|
|
{
|
|
case REG_SZ:
|
|
GetRegsz(hCurrentKey, pszKey, &pValues[i].pvValue,
|
|
&pValues[i].dwLength);
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
GetRegdw(hCurrentKey, pszKey, &pValues[i].pvValue,
|
|
&pValues[i].dwLength);
|
|
break;
|
|
|
|
case REG_EXPAND_SZ:
|
|
GetRegesz(hCurrentKey, pszKey, &pValues[i].pvValue,
|
|
&pValues[i].dwLength);
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
GetRegmsz(hCurrentKey, pszKey, &pValues[i].pvValue,
|
|
&pValues[i].dwLength);
|
|
break;
|
|
|
|
case REG_BINARY:
|
|
DbgP(( TEXT("%s is a REG_BINARY and won't be duplicated\n"), pszKey ));
|
|
break;
|
|
|
|
default:
|
|
DbgP(( TEXT("%s is an unknown type; %d (decimal)\n"), pszKey, dwType ));
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a REG_SZ value and stick it in the table entry, along with the
|
|
// length
|
|
//
|
|
|
|
BOOL GetRegsz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD *pdwLength)
|
|
{
|
|
BYTE achValue[1024];
|
|
|
|
DWORD dwLength;
|
|
LONG Status;
|
|
DWORD dwType = REG_SZ;
|
|
PBYTE pszValue = NULL;
|
|
|
|
|
|
|
|
if ( (NULL == pszKey) || (NULL == ppvValue) ||
|
|
(NULL == hKey) || (NULL == pdwLength))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
FillMemory(achValue, sizeof(achValue), 0xcd);
|
|
#endif
|
|
|
|
dwLength = sizeof(achValue);
|
|
|
|
|
|
Status = RegQueryValueEx( hKey,
|
|
pszKey,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &achValue[0],
|
|
&dwLength);
|
|
|
|
if ((ERROR_SUCCESS != Status) || (REG_SZ != dwType) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pszValue = malloc(dwLength);
|
|
|
|
if (NULL == pszValue)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
CopyMemory(pszValue, achValue, dwLength);
|
|
|
|
*ppvValue = pszValue;
|
|
*pdwLength = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Get the value of a REG_EXPAND_SZ and its length
|
|
//
|
|
|
|
BOOL GetRegesz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength)
|
|
{
|
|
BYTE achValue[1024];
|
|
|
|
DWORD dwLength;
|
|
LONG Status;
|
|
DWORD dwType = REG_EXPAND_SZ;
|
|
PBYTE pszValue = NULL;
|
|
|
|
|
|
if ( (NULL == pszKey) || (NULL == ppvValue) ||
|
|
(NULL == hKey) || (NULL == pdwLength))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
FillMemory(achValue, sizeof(achValue), 0xcd);
|
|
#endif
|
|
|
|
dwLength = sizeof(achValue);
|
|
|
|
Status = RegQueryValueEx( hKey,
|
|
pszKey,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &achValue[0],
|
|
&dwLength);
|
|
|
|
if ((ERROR_SUCCESS != Status) || (REG_EXPAND_SZ != dwType))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pszValue = malloc(dwLength);
|
|
|
|
if (NULL == pszValue)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory(pszValue, achValue, dwLength);
|
|
|
|
*ppvValue = pszValue;
|
|
*pdwLength = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Get value and length of REG_MULTI_SZ
|
|
//
|
|
|
|
BOOL GetRegmsz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength)
|
|
{
|
|
//BYTE achValue[1024];
|
|
BYTE achValue[2048]; // careful, some of these strings are quite long
|
|
|
|
DWORD dwLength;
|
|
LONG Status;
|
|
DWORD dwType = REG_MULTI_SZ;
|
|
PBYTE pszValue = NULL;
|
|
|
|
|
|
if ( (NULL == pszKey) || (NULL == ppvValue) ||
|
|
(NULL == hKey) || (NULL == pdwLength))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
FillMemory(achValue, sizeof(achValue), 0xcd);
|
|
#endif
|
|
|
|
|
|
dwLength = sizeof(achValue);
|
|
|
|
|
|
Status = RegQueryValueEx( hKey,
|
|
pszKey,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &achValue[0],
|
|
&dwLength);
|
|
|
|
if ((ERROR_SUCCESS != Status) || (REG_MULTI_SZ != dwType))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pszValue = malloc(dwLength);
|
|
|
|
if (NULL == pszValue)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory(pszValue, achValue, dwLength);
|
|
|
|
*ppvValue = pszValue;
|
|
*pdwLength = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Get value and length of REG_DWORD
|
|
//
|
|
|
|
|
|
BOOL GetRegdw(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength)
|
|
{
|
|
DWORD dwValue = 0;
|
|
|
|
DWORD dwLength;
|
|
LONG Status;
|
|
DWORD dwType = REG_DWORD;
|
|
|
|
|
|
|
|
if ( (NULL == pszKey) || (NULL == ppvValue) ||
|
|
(NULL == hKey) || (NULL == pdwLength) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
dwLength = sizeof(dwValue);
|
|
|
|
|
|
Status = RegQueryValueEx( hKey,
|
|
pszKey,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) &dwValue,
|
|
&dwLength);
|
|
|
|
if ((ERROR_SUCCESS != Status) || (REG_DWORD != dwType))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*ppvValue = (PVOID) (ULONG_PTR) dwValue;
|
|
*pdwLength = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
WriteRegistryKeyValues(
|
|
HKEY hCurrentKey,
|
|
DWORD NumberOfValues,
|
|
PREGENTRY pValues)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a bunch of values associated with a given key.
|
|
|
|
Arguments:
|
|
|
|
hCurrentKey - the key
|
|
|
|
NumberOfValues - the number of values
|
|
|
|
pValues - the array of values
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
|
|
|
|
for (i = 0; i < NumberOfValues; i++)
|
|
{
|
|
DWORD dwType;
|
|
PVOID pvValue;
|
|
DWORD dwLength;
|
|
LPTSTR pszKey;
|
|
|
|
pszKey = pValues[i].pszKey;
|
|
dwType = pValues[i].dwType;
|
|
dwLength = pValues[i].dwLength;
|
|
pvValue = pValues[i].pvValue;
|
|
|
|
switch (dwType)
|
|
{
|
|
case REG_SZ:
|
|
AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue);
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
AddValue(hCurrentKey, pszKey, dwType, dwLength, &pvValue);
|
|
break;
|
|
|
|
case REG_EXPAND_SZ:
|
|
AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue);
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue);
|
|
break;
|
|
|
|
case REG_BINARY:
|
|
//
|
|
// There are no binary values we need to copy. If we did, we'd
|
|
// put something here
|
|
//
|
|
|
|
break;
|
|
|
|
default:
|
|
DbgP(( TEXT("%s is an unknown type; %d (decimal)\n"), pszKey, dwType ));
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open a key so we can read the values
|
|
//
|
|
|
|
|
|
BOOL OpenKey(
|
|
LPTSTR pszKey,
|
|
PHKEY phKey)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a registry key.
|
|
|
|
Arguments:
|
|
|
|
pszKey - the name of the key relative to HKEY_LOCAL_MACHINE
|
|
|
|
phKey - the key handlle
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
HKEY hNewKey = 0;
|
|
DWORD Status;
|
|
|
|
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
pszKey,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hNewKey);
|
|
|
|
if (ERROR_SUCCESS != Status)
|
|
{
|
|
*phKey = NULL;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
*phKey = hNewKey;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CreateKey(LPTSTR pszKey, PHKEY phKey)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a registry key.
|
|
|
|
Arguments:
|
|
|
|
pszKey - the name of the key relative to HKEY_LOCAL_MACHINE
|
|
|
|
phKey - the key handlle
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LONG Status;
|
|
DWORD Disposition;
|
|
|
|
Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
|
pszKey,
|
|
0,
|
|
REG_NONE,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
phKey,
|
|
&Disposition);
|
|
|
|
if ( ERROR_SUCCESS == Status)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DbgP(( TEXT("error creating key %s Status %d\n"), pszKey, Status ));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Add a value to the registry
|
|
//
|
|
|
|
|
|
BOOL AddValue(HKEY hKey, LPTSTR pszKey, DWORD dwType, DWORD dwLength, PVOID pvValue)
|
|
{
|
|
|
|
BOOL fSuccess = TRUE;
|
|
LONG Status = ERROR_SUCCESS;
|
|
HANDLE th;
|
|
|
|
Status = RegSetValueEx( hKey,
|
|
pszKey,
|
|
0,
|
|
dwType,
|
|
pvValue,
|
|
dwLength);
|
|
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
fSuccess = FALSE;
|
|
//RegCloseKey(hKey);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
int _cdecl _vsnwprintf( wchar_t *buffer, size_t count, wchar_t *format, va_list arg_ptr);
|
|
|
|
// Format and write debug information to OutputDebugString
|
|
ULONG
|
|
_cdecl
|
|
DbgPrint(
|
|
LPTSTR Format,
|
|
...
|
|
)
|
|
{
|
|
ULONG rc = 0;
|
|
TCHAR szbuffer[256];
|
|
|
|
va_list marker;
|
|
va_start( marker, Format );
|
|
{
|
|
rc = _vsnwprintf( szbuffer, 254, Format, marker );
|
|
szbuffer[255] = (TCHAR)0;
|
|
OutputDebugString( TRACE_TAG );
|
|
OutputDebugString( szbuffer );
|
|
}
|
|
|
|
return rc;
|
|
}
|