1125 lines
24 KiB
C
1125 lines
24 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (C) 1999 Microsoft Coporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
main.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
main module
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <precomp.h>
|
||
|
#include <dhcpexim.h>
|
||
|
|
||
|
BOOL GlobalIsNT4, GlobalIsNT5;
|
||
|
WCHAR CurrentDir[MAX_PATH*2];
|
||
|
|
||
|
CRITICAL_SECTION DhcpGlobalMemoryCritSect;
|
||
|
CRITICAL_SECTION DhcpGlobalInProgressCritSect;
|
||
|
CHAR DhcpEximOemDatabaseName[2048];
|
||
|
CHAR DhcpEximOemDatabasePath[2048];
|
||
|
HANDLE hLog;
|
||
|
|
||
|
BOOL IsNT4( VOID ) {
|
||
|
return GlobalIsNT4;
|
||
|
}
|
||
|
|
||
|
BOOL IsNT5( VOID ) {
|
||
|
return GlobalIsNT5;
|
||
|
}
|
||
|
|
||
|
#define MAX_PRINTF_LEN 4096
|
||
|
char OutputBuf[MAX_PRINTF_LEN];
|
||
|
|
||
|
VOID
|
||
|
StartDebugLog(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
CHAR Buffer[MAX_PATH*2];
|
||
|
|
||
|
if( NULL != hLog ) return;
|
||
|
|
||
|
if( 0 == GetWindowsDirectoryA( Buffer, MAX_PATH )) {
|
||
|
ZeroMemory(Buffer, sizeof(Buffer));
|
||
|
}
|
||
|
|
||
|
if( Buffer[strlen(Buffer)-1] != '\\' ) {
|
||
|
strcat(Buffer, "\\");
|
||
|
}
|
||
|
strcat(Buffer, "dhcpexim.log");
|
||
|
|
||
|
hLog = CreateFileA(
|
||
|
Buffer, GENERIC_WRITE,
|
||
|
FILE_SHARE_READ, NULL, OPEN_ALWAYS,
|
||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
||
|
NULL );
|
||
|
|
||
|
if( hLog == INVALID_HANDLE_VALUE) {
|
||
|
hLog = NULL;
|
||
|
}
|
||
|
|
||
|
if(GetLastError() == ERROR_ALREADY_EXISTS) {
|
||
|
//
|
||
|
// Appending to existing file
|
||
|
//
|
||
|
|
||
|
SetFilePointer(hLog,0,NULL,FILE_END);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CloseDebugLog(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if( hLog ) {
|
||
|
CloseHandle( hLog );
|
||
|
hLog = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
Tr(
|
||
|
IN LPSTR Format,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
va_list ArgList;
|
||
|
ULONG Length;
|
||
|
|
||
|
strcpy(OutputBuf, "[DHCP] ");
|
||
|
Length = strlen(OutputBuf);
|
||
|
|
||
|
va_start(ArgList, Format);
|
||
|
Length = vsprintf(&OutputBuf[Length], Format, ArgList );
|
||
|
va_end(ArgList);
|
||
|
|
||
|
#if DBG
|
||
|
DbgPrint( (PCH)OutputBuf );
|
||
|
#endif
|
||
|
|
||
|
if( hLog ) {
|
||
|
DWORD Size = strlen(OutputBuf);
|
||
|
WriteFile(
|
||
|
hLog, OutputBuf, Size, &Size, NULL );
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsPostW2k(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
DWORD Error, Type, Value, Size;
|
||
|
|
||
|
|
||
|
Error = RegOpenKeyEx(
|
||
|
HKEY_LOCAL_MACHINE,
|
||
|
TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
|
||
|
0, KEY_READ, &hKey );
|
||
|
|
||
|
if( NO_ERROR != Error ) return FALSE;
|
||
|
|
||
|
Type = REG_DWORD; Value = 0; Size = sizeof(Value);
|
||
|
Error = RegQueryValueEx(
|
||
|
hKey, TEXT("Version"), NULL, &Type, (PVOID)&Value, &Size );
|
||
|
|
||
|
RegCloseKey( hKey );
|
||
|
|
||
|
//
|
||
|
// if this value is not present, then upgrade is needed
|
||
|
//
|
||
|
|
||
|
return (Error == NO_ERROR );
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ReconcileLocalService(
|
||
|
IN PULONG Subnets,
|
||
|
IN DWORD nSubnets OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine reconciles the specified scopes.
|
||
|
This is needed after importing as the import doesnt
|
||
|
actually get the bitmask, but only the database entries.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD Error, FinalError, nRead, nTotal, i;
|
||
|
DHCP_RESUME_HANDLE Resume = 0;
|
||
|
LPDHCP_IP_ARRAY IpArray;
|
||
|
|
||
|
if( 0 == nSubnets ) {
|
||
|
IpArray = NULL;
|
||
|
Error = DhcpEnumSubnets(
|
||
|
L"127.0.0.1", &Resume, (ULONG)(-1), &IpArray, &nRead,
|
||
|
&nTotal );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpEnumSubnets: %ld\n", Error);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
if( 0 == nRead || 0 == nTotal || IpArray->NumElements == 0 ) {
|
||
|
Tr("DhcpEnumSubnets returned none." );
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
Error = ReconcileLocalService(
|
||
|
IpArray->Elements, IpArray->NumElements );
|
||
|
|
||
|
DhcpRpcFreeMemory( IpArray );
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reconcile each of the specified scopes
|
||
|
//
|
||
|
|
||
|
FinalError = NO_ERROR;
|
||
|
for( i = 0; i < nSubnets ; i ++ ) {
|
||
|
LPDHCP_SCAN_LIST ScanList = NULL;
|
||
|
|
||
|
Error = DhcpScanDatabase(
|
||
|
L"127.0.0.1", Subnets[i], TRUE, &ScanList);
|
||
|
|
||
|
if( NULL != ScanList ) DhcpRpcFreeMemory( ScanList );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpScanDatabase(0x%lx): %ld\n", Subnets[i], Error);
|
||
|
FinalError = Error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FinalError;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
InitializeAndGetServiceConfig(
|
||
|
OUT PM_SERVER *pServer
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine initializes all the modules and obtains the
|
||
|
configuration for the service
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD Error;
|
||
|
OSVERSIONINFO Ver;
|
||
|
extern DWORD ClassIdRunningCount; // defined in mm\classdefl.c
|
||
|
|
||
|
//
|
||
|
// Initialize globals
|
||
|
//
|
||
|
|
||
|
GlobalIsNT4 = FALSE;
|
||
|
GlobalIsNT5 = FALSE;
|
||
|
|
||
|
try {
|
||
|
InitializeCriticalSection( &DhcpGlobalMemoryCritSect );
|
||
|
InitializeCriticalSection( &DhcpGlobalInProgressCritSect );
|
||
|
}except ( EXCEPTION_EXECUTE_HANDLER )
|
||
|
{
|
||
|
Error = GetLastError( );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
ClassIdRunningCount = 0x1000;
|
||
|
|
||
|
//
|
||
|
// Other initialization
|
||
|
//
|
||
|
|
||
|
Error = NO_ERROR;
|
||
|
Ver.dwOSVersionInfoSize = sizeof(Ver);
|
||
|
if( FALSE == GetVersionEx(&Ver) ) return GetLastError();
|
||
|
if( Ver.dwMajorVersion == 4 ) GlobalIsNT4 = TRUE;
|
||
|
else if( Ver.dwMajorVersion == 5 ) GlobalIsNT5 = TRUE;
|
||
|
else if( Ver.dwMajorVersion < 4 ) return ERROR_NOT_SUPPORTED;
|
||
|
|
||
|
if( GlobalIsNT5 && IsPostW2k() ) GlobalIsNT5 = FALSE;
|
||
|
|
||
|
#if DBG
|
||
|
DbgPrint("Is NT4: %s, Is NT5: %s\n",
|
||
|
GlobalIsNT4 ? "yes" : "no",
|
||
|
GlobalIsNT5 ? "yes" : "no" );
|
||
|
|
||
|
StartDebugLog();
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
SaveBufSize = 0;
|
||
|
SaveBuf = LocalAlloc( LPTR, SAVE_BUF_SIZE );
|
||
|
if( NULL == SaveBuf ) {
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
|
||
|
Error = GetCurrentDirectoryW(
|
||
|
sizeof(CurrentDir)/sizeof(WCHAR), CurrentDir );
|
||
|
if( 0 != Error ) {
|
||
|
Error = NO_ERROR;
|
||
|
} else {
|
||
|
Error = GetLastError();
|
||
|
Tr("GetCurrentDirectoryW: %ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set right permissions on the db directory etc..
|
||
|
//
|
||
|
|
||
|
Error = InitializeDatabaseParameters();
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("InitializeDatabaseParameters: %ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now obtain the configuration
|
||
|
//
|
||
|
|
||
|
if( !GlobalIsNT4 && !GlobalIsNT5 ) {
|
||
|
//
|
||
|
// Whistler configuration should be read from the
|
||
|
// database..
|
||
|
//
|
||
|
|
||
|
Error = DhcpeximReadDatabaseConfiguration(pServer);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximReadDatabaseConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// NT4 or W2K configuration should be read from registry..
|
||
|
//
|
||
|
|
||
|
Error = DhcpeximReadRegistryConfiguration(pServer);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximReadRegistryConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CleanupServiceConfig(
|
||
|
IN OUT PM_SERVER Server
|
||
|
)
|
||
|
{
|
||
|
DWORD Error;
|
||
|
|
||
|
if( NULL != SaveBuf ) LocalFree(SaveBuf);
|
||
|
SaveBuf = NULL;
|
||
|
SaveBufSize = 0;
|
||
|
|
||
|
if( NULL != Server ) MemServerFree(Server);
|
||
|
Error = CleanupDatabaseParameters();
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("CleanupServiceConfig: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
if( FALSE == SetCurrentDirectoryW(CurrentDir) ) {
|
||
|
if( NO_ERROR == Error ) Error = GetLastError();
|
||
|
Tr("SetCurrentDirectoryW: %ld\n", GetLastError());
|
||
|
}
|
||
|
|
||
|
CloseDebugLog();
|
||
|
|
||
|
DeleteCriticalSection( &DhcpGlobalMemoryCritSect );
|
||
|
DeleteCriticalSection( &DhcpGlobalInProgressCritSect );
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ExportConfiguration(
|
||
|
IN OUT PM_SERVER SvcConfig,
|
||
|
IN ULONG *Subnets,
|
||
|
IN ULONG nSubnets,
|
||
|
IN HANDLE hFile
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine attempts to save the service configuration to a
|
||
|
file after selecting the required subnets.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD Error;
|
||
|
|
||
|
//
|
||
|
// First select the required subnets and get this
|
||
|
// configuration alone.
|
||
|
//
|
||
|
|
||
|
Error = SelectConfiguration( SvcConfig, Subnets, nSubnets );
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
//
|
||
|
// Save the configuration to the specified file handle
|
||
|
//
|
||
|
|
||
|
hTextFile = hFile;
|
||
|
Error = SaveConfigurationToFile(SvcConfig);
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
//
|
||
|
// Now try to save the database entries to file
|
||
|
//
|
||
|
|
||
|
Error = SaveDatabaseEntriesToFile(Subnets, nSubnets);
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
Tr("ExportConfiguration succeeded\n");
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ImportConfiguration(
|
||
|
IN OUT PM_SERVER SvcConfig,
|
||
|
IN ULONG *Subnets,
|
||
|
IN ULONG nSubnets,
|
||
|
IN LPBYTE Mem, // import file : shared mem
|
||
|
IN ULONG MemSize // shared mem size
|
||
|
)
|
||
|
{
|
||
|
DWORD Error;
|
||
|
PM_SERVER Server;
|
||
|
|
||
|
//
|
||
|
// First obtain the configuration from the file
|
||
|
//
|
||
|
|
||
|
Error = ReadDbEntries( &Mem, &MemSize, &Server );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("ReadDbEntries: %ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Select the configuration required
|
||
|
//
|
||
|
|
||
|
Error = SelectConfiguration( Server, Subnets, nSubnets );
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
//
|
||
|
// Merge the configuration along with the svc configuration
|
||
|
//
|
||
|
Error = MergeConfigurations( SvcConfig, Server );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("MergeConfigurations: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
MemServerFree( Server );
|
||
|
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
//
|
||
|
// Now save the new configuration to registry/disk
|
||
|
//
|
||
|
if( !GlobalIsNT5 && !GlobalIsNT4 ) {
|
||
|
//
|
||
|
// Whistler has config in database
|
||
|
//
|
||
|
Error = DhcpeximWriteDatabaseConfiguration(SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
} else {
|
||
|
Error = DhcpeximWriteRegistryConfiguration(SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( NO_ERROR != Error ) return Error;
|
||
|
|
||
|
//
|
||
|
// Now read the database entries from file and stash them
|
||
|
// into the db.
|
||
|
//
|
||
|
|
||
|
Error = SaveFileEntriesToDatabase(
|
||
|
Mem, MemSize, Subnets, nSubnets );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SaveFileEntriesToDatabase: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
IpAddressToStringW(
|
||
|
IN DWORD IpAddress,
|
||
|
IN LPWSTR String // must have enough space preallocated
|
||
|
)
|
||
|
{
|
||
|
PUCHAR pAddress;
|
||
|
ULONG Size;
|
||
|
|
||
|
pAddress = (PUCHAR)&IpAddress;
|
||
|
wsprintf(String, L"%ld.%ld.%ld.%ld",
|
||
|
pAddress[3], pAddress[2], pAddress[1], pAddress[0] );
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
StringToIpAddressW(
|
||
|
LPWSTR pwszString
|
||
|
)
|
||
|
{
|
||
|
DWORD dwStrlen = 0;
|
||
|
DWORD dwLen = 0;
|
||
|
DWORD dwRes = 0;
|
||
|
LPSTR pszString = NULL;
|
||
|
if( pwszString == NULL )
|
||
|
return dwRes;
|
||
|
|
||
|
pszString = DhcpUnicodeToOem(pwszString, NULL);
|
||
|
if( pszString )
|
||
|
{
|
||
|
dwRes = DhcpDottedStringToIpAddress(pszString);
|
||
|
}
|
||
|
|
||
|
return dwRes;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CmdLineDoImport(
|
||
|
IN LPWSTR *Args,
|
||
|
IN ULONG nArgs
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Syntax: Import <filename> <ALL/subnets>
|
||
|
//
|
||
|
LPWSTR FileName;
|
||
|
ULONG Subnets[1024],*pSubnets, nSubnets, MemSize, Error;
|
||
|
HANDLE hFile;
|
||
|
LPBYTE Mem;
|
||
|
PM_SERVER SvcConfig, FileConfig;
|
||
|
|
||
|
if( nArgs == 1 ) return ERROR_BAD_ARGUMENTS;
|
||
|
|
||
|
FileName = Args[0]; Args ++ ; nArgs --;
|
||
|
|
||
|
//
|
||
|
// First open the file
|
||
|
//
|
||
|
|
||
|
Error = OpenTextFile(
|
||
|
FileName, TRUE, &hFile, &Mem, &MemSize );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("OpenTextFileForRead: %ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now try to parse the rest of the arguments to see if they
|
||
|
// are all ok
|
||
|
//
|
||
|
|
||
|
if( _wcsicmp(Args[0],L"ALL") == 0 ) {
|
||
|
nSubnets = 0; pSubnets = NULL;
|
||
|
} else {
|
||
|
pSubnets = Subnets;
|
||
|
nSubnets = 0;
|
||
|
while( nArgs -- ) {
|
||
|
pSubnets[nSubnets++] = StringToIpAddressW(*Args++);
|
||
|
if( pSubnets[nSubnets-1] == INADDR_ANY ||
|
||
|
pSubnets[nSubnets-1] == INADDR_NONE ) {
|
||
|
Error = ERROR_BAD_ARGUMENTS;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize parameters
|
||
|
//
|
||
|
|
||
|
Error = InitializeAndGetServiceConfig( &SvcConfig );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("InitializeAndGetServiceConfig: %ld\n", Error );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Error = ImportConfiguration(
|
||
|
SvcConfig, pSubnets, nSubnets, Mem, MemSize );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("ImportConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finally cleanup
|
||
|
//
|
||
|
|
||
|
CleanupServiceConfig(SvcConfig);
|
||
|
|
||
|
//
|
||
|
// Also reconcile local server
|
||
|
//
|
||
|
|
||
|
ReconcileLocalService(pSubnets, nSubnets);
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
CloseTextFile( hFile, Mem );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
CmdLineDoExport(
|
||
|
IN LPWSTR *Args,
|
||
|
IN ULONG nArgs
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Syntax: Import <filename> <ALL/subnets>
|
||
|
//
|
||
|
LPWSTR FileName;
|
||
|
ULONG Subnets[1024],*pSubnets, nSubnets, MemSize, Error;
|
||
|
HANDLE hFile;
|
||
|
LPBYTE Mem;
|
||
|
PM_SERVER SvcConfig, FileConfig;
|
||
|
|
||
|
if( nArgs == 1 ) return ERROR_BAD_ARGUMENTS;
|
||
|
|
||
|
FileName = Args[0]; Args ++ ; nArgs --;
|
||
|
|
||
|
//
|
||
|
// First open the file
|
||
|
//
|
||
|
|
||
|
Error = OpenTextFile(
|
||
|
FileName, FALSE, &hFile, &Mem, &MemSize );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("OpenTextFileForRead: %ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now try to parse the rest of the arguments to see if they
|
||
|
// are all ok
|
||
|
//
|
||
|
|
||
|
if( _wcsicmp(Args[0],L"ALL") == 0 ) {
|
||
|
nSubnets = 0; pSubnets = NULL;
|
||
|
} else {
|
||
|
pSubnets = Subnets;
|
||
|
nSubnets = 0;
|
||
|
while( nArgs -- ) {
|
||
|
pSubnets[nSubnets++] = StringToIpAddressW(*Args++);
|
||
|
if( pSubnets[nSubnets-1] == INADDR_ANY ||
|
||
|
pSubnets[nSubnets-1] == INADDR_NONE ) {
|
||
|
Error = ERROR_BAD_ARGUMENTS;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize parameters
|
||
|
//
|
||
|
|
||
|
Error = InitializeAndGetServiceConfig( &SvcConfig );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("InitializeAndGetServiceConfig: %ld\n", Error );
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Export configuration
|
||
|
//
|
||
|
|
||
|
Error = ExportConfiguration(
|
||
|
SvcConfig, pSubnets, nSubnets, hFile );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("ExportConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finally cleanup
|
||
|
//
|
||
|
|
||
|
CleanupServiceConfig(SvcConfig);
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
CloseTextFile( hFile, Mem );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
PM_SERVER
|
||
|
DhcpGetCurrentServer(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
ASSERT( FALSE );
|
||
|
//
|
||
|
// This is there only to let teh compiler compile without
|
||
|
// having to include dhcpssvc.lib. This routine should never
|
||
|
// be called at all
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SubnetMatches(
|
||
|
IN DWORD IpAddress,
|
||
|
IN ULONG *Subnets,
|
||
|
IN ULONG nSubnets
|
||
|
)
|
||
|
{
|
||
|
if( 0 == nSubnets || NULL == Subnets ) return TRUE;
|
||
|
while( nSubnets -- ) {
|
||
|
if( IpAddress == *Subnets ++) return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DisableLocalScopes(
|
||
|
IN ULONG *Subnets,
|
||
|
IN ULONG nSubnets
|
||
|
)
|
||
|
{
|
||
|
DWORD Error;
|
||
|
PM_SERVER SvcConfig;
|
||
|
ARRAY_LOCATION Loc;
|
||
|
PM_SUBNET Subnet;
|
||
|
|
||
|
Error = InitializeAndGetServiceConfig(&SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DisableLocalScopes: Init: %ld\n", Error );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Error = MemArrayInitLoc(&SvcConfig->Subnets, &Loc);
|
||
|
while( NO_ERROR == Error ) {
|
||
|
Error = MemArrayGetElement(
|
||
|
&SvcConfig->Subnets, &Loc, &Subnet);
|
||
|
ASSERT( NO_ERROR == Error && NULL != Subnet );
|
||
|
|
||
|
//
|
||
|
// Disable the subnet
|
||
|
//
|
||
|
|
||
|
if( SubnetMatches(Subnet->Address, Subnets, nSubnets ) ) {
|
||
|
Subnet->State = DISABLED(Subnet->State);
|
||
|
}
|
||
|
|
||
|
Error = MemArrayNextLoc(
|
||
|
&SvcConfig->Subnets, &Loc);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now save the new configuration to registry/disk
|
||
|
//
|
||
|
|
||
|
if( !GlobalIsNT5 && !GlobalIsNT4 ) {
|
||
|
//
|
||
|
// Whistler has config in database
|
||
|
//
|
||
|
Error = DhcpeximWriteDatabaseConfiguration(SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
} else {
|
||
|
Error = DhcpeximWriteRegistryConfiguration(SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CleanupServiceConfig(SvcConfig);
|
||
|
}
|
||
|
|
||
|
|
||
|
LPWSTR
|
||
|
MakeName(
|
||
|
IN DWORD IpAddress,
|
||
|
IN LPWSTR Name
|
||
|
)
|
||
|
{
|
||
|
static WCHAR Buffer[40];
|
||
|
PUCHAR pAddress;
|
||
|
LPWSTR RetVal;
|
||
|
ULONG Size;
|
||
|
|
||
|
pAddress = (PUCHAR)&IpAddress;
|
||
|
wsprintf(Buffer, L"[%d.%d.%d.%d] ", pAddress[3], pAddress[2],
|
||
|
pAddress[1], pAddress[0] );
|
||
|
|
||
|
Size = wcslen(Buffer)+1;
|
||
|
if( NULL != Name ) Size += wcslen(Name);
|
||
|
|
||
|
RetVal = LocalAlloc( LPTR, Size * sizeof(WCHAR));
|
||
|
if( NULL == RetVal ) return NULL;
|
||
|
|
||
|
wcscpy(RetVal, Buffer);
|
||
|
if( NULL != Name ) wcscat(RetVal, Name );
|
||
|
|
||
|
return RetVal;
|
||
|
}
|
||
|
DWORD
|
||
|
InitializeCtxt(
|
||
|
IN OUT PDHCPEXIM_CONTEXT Ctxt,
|
||
|
IN PM_SERVER Server
|
||
|
)
|
||
|
{
|
||
|
DWORD Error,i, Size;
|
||
|
ARRAY_LOCATION Loc;
|
||
|
PM_SUBNET Subnet;
|
||
|
|
||
|
//
|
||
|
// First find the # of subnets and allocate array
|
||
|
//
|
||
|
Ctxt->nScopes = i = MemArraySize(&Server->Subnets);
|
||
|
Ctxt->Scopes = LocalAlloc(LPTR, i * sizeof(Ctxt->Scopes[0]) );
|
||
|
if( NULL == Ctxt->Scopes ) {
|
||
|
Ctxt->nScopes = 0;
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Walk through the array and setup each element
|
||
|
//
|
||
|
|
||
|
i = 0;
|
||
|
Error = MemArrayInitLoc( &Server->Subnets, &Loc );
|
||
|
while( NO_ERROR == Error ) {
|
||
|
Error = MemArrayGetElement(&Server->Subnets, &Loc, &Subnet );
|
||
|
ASSERT(NO_ERROR == Error );
|
||
|
|
||
|
Ctxt->Scopes[i].SubnetAddress = Subnet->Address;
|
||
|
Ctxt->Scopes[i].SubnetName = MakeName(Subnet->Address, Subnet->Name);
|
||
|
if( NULL == Ctxt->Scopes[i].SubnetName ) return GetLastError();
|
||
|
|
||
|
i ++;
|
||
|
Error = MemArrayNextLoc(&Server->Subnets, &Loc );
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
DhcpEximInitializeContext(
|
||
|
IN OUT PDHCPEXIM_CONTEXT Ctxt,
|
||
|
IN LPWSTR FileName,
|
||
|
IN BOOL fExport
|
||
|
)
|
||
|
{
|
||
|
DWORD Error;
|
||
|
LPVOID Mem;
|
||
|
|
||
|
ZeroMemory(Ctxt, sizeof(*Ctxt));
|
||
|
|
||
|
//
|
||
|
// First set the FileName and fExport fields
|
||
|
//
|
||
|
Ctxt->FileName = FileName;
|
||
|
Ctxt->fExport = fExport;
|
||
|
|
||
|
//
|
||
|
// Next open the file.
|
||
|
//
|
||
|
Error = OpenTextFile(
|
||
|
FileName, !fExport, &Ctxt->hFile, &Ctxt->Mem,
|
||
|
&Ctxt->MemSize );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("OpenTextFileForRead:%ld\n", Error );
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize parameters and obtain config
|
||
|
//
|
||
|
|
||
|
Error = InitializeAndGetServiceConfig(
|
||
|
(PM_SERVER*)&Ctxt->SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("InitializeAndGetServiceConfig: %ld\n", Error );
|
||
|
|
||
|
CloseTextFile(Ctxt->hFile, Ctxt->Mem);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
//
|
||
|
// If this is an import, the configuration from the file
|
||
|
// should also be read.
|
||
|
//
|
||
|
|
||
|
if( !fExport ) {
|
||
|
|
||
|
Error = ReadDbEntries(
|
||
|
&Ctxt->Mem, &Ctxt->MemSize,
|
||
|
(PM_SERVER*)&Ctxt->FileConfig );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("ReadDbEntries: %ld\n", Error );
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate and initialize the Ctxt data structures with the
|
||
|
// service scopes info in case of EXPORT
|
||
|
//
|
||
|
|
||
|
Error = InitializeCtxt(
|
||
|
Ctxt, fExport ? Ctxt->SvcConfig : Ctxt->FileConfig );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("InitializeCtxt: %ld\n", Error );
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
} while( 0 );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
|
||
|
CleanupServiceConfig( Ctxt->SvcConfig );
|
||
|
if( NULL != Ctxt->FileConfig ) {
|
||
|
MemServerFree( (PM_SERVER)Ctxt->FileConfig );
|
||
|
}
|
||
|
CloseTextFile( Ctxt->hFile, Ctxt->Mem );
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CalculateSubnets(
|
||
|
IN PDHCPEXIM_CONTEXT Ctxt,
|
||
|
OUT PULONG *Subnets,
|
||
|
OUT ULONG *nSubnets
|
||
|
)
|
||
|
{
|
||
|
DWORD Error, i;
|
||
|
PULONG pSubnets;
|
||
|
|
||
|
//
|
||
|
// First check if there is atleast one unselected subnet
|
||
|
//
|
||
|
(*nSubnets) = 0;
|
||
|
|
||
|
for( i = 0; i < Ctxt->nScopes; i ++ ) {
|
||
|
if( Ctxt->Scopes[i].fSelected ) (*nSubnets) ++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Special case if all subnets are selected
|
||
|
//
|
||
|
|
||
|
if( *nSubnets == Ctxt->nScopes ) {
|
||
|
*nSubnets = 0;
|
||
|
*Subnets = NULL;
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate memory
|
||
|
//
|
||
|
|
||
|
*Subnets = LocalAlloc( LPTR, sizeof(DWORD)* (*nSubnets));
|
||
|
if( NULL == *Subnets ) return GetLastError();
|
||
|
|
||
|
//
|
||
|
// Copy the subnets
|
||
|
//
|
||
|
|
||
|
(*nSubnets) = 0;
|
||
|
for( i = 0; i < Ctxt->nScopes; i ++ ) {
|
||
|
if( Ctxt->Scopes[i].fSelected ) {
|
||
|
(*Subnets)[(*nSubnets)++] = Ctxt->Scopes[i].SubnetAddress;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
DhcpEximCleanupContext(
|
||
|
IN OUT PDHCPEXIM_CONTEXT Ctxt,
|
||
|
IN BOOL fAbort
|
||
|
)
|
||
|
{
|
||
|
DWORD Error, i;
|
||
|
DWORD *Subnets, nSubnets;
|
||
|
|
||
|
Error = NO_ERROR;
|
||
|
Subnets = NULL;
|
||
|
nSubnets = 0;
|
||
|
|
||
|
//
|
||
|
// If not aborting, attempt to execute the operation
|
||
|
//
|
||
|
if( !fAbort ) do {
|
||
|
Error = CalculateSubnets( Ctxt, &Subnets, &nSubnets );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("CalculateSubnets: %ld\n", Error );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( Ctxt->fExport ) {
|
||
|
//
|
||
|
// Export the specified subnets out
|
||
|
//
|
||
|
|
||
|
Error = SelectConfiguration(
|
||
|
Ctxt->SvcConfig, Subnets, nSubnets );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SelectConfiguration: %ld\n", Error );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Error = SaveConfigurationToFile( Ctxt->SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SaveConfigurationToFile: %ld\n", Error );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now try to save the database entries to file
|
||
|
//
|
||
|
|
||
|
Error = SaveDatabaseEntriesToFile(Subnets, nSubnets);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SaveDatabaseEntriesToFile: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Import the specified subnets in
|
||
|
//
|
||
|
|
||
|
Error = SelectConfiguration(
|
||
|
Ctxt->FileConfig, Subnets, nSubnets );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SelectConfiguration: %ld\n", Error );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Error = MergeConfigurations(
|
||
|
Ctxt->SvcConfig, Ctxt->FileConfig );
|
||
|
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("MergeConfigurations: %ld\n", Error );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Now save the new configuration to registry/disk
|
||
|
//
|
||
|
if( !GlobalIsNT5 && !GlobalIsNT4 ) {
|
||
|
//
|
||
|
// Whistler has config in database
|
||
|
//
|
||
|
Error = DhcpeximWriteDatabaseConfiguration(Ctxt->SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
} else {
|
||
|
Error = DhcpeximWriteRegistryConfiguration(Ctxt->SvcConfig);
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( NO_ERROR != Error ) break;
|
||
|
|
||
|
//
|
||
|
// Now read the database entries from file and stash them
|
||
|
// into the db.
|
||
|
//
|
||
|
|
||
|
Error = SaveFileEntriesToDatabase(
|
||
|
Ctxt->Mem, Ctxt->MemSize, Subnets, nSubnets );
|
||
|
if( NO_ERROR != Error ) {
|
||
|
Tr("SaveFileEntriesToDatabase: %ld\n", Error );
|
||
|
}
|
||
|
|
||
|
} while( 0 );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Cleanup
|
||
|
//
|
||
|
|
||
|
if( NULL != Ctxt->SvcConfig ) {
|
||
|
CleanupServiceConfig( Ctxt->SvcConfig );
|
||
|
}
|
||
|
|
||
|
if( NULL != Ctxt->FileConfig ) {
|
||
|
MemServerFree( (PM_SERVER)Ctxt->FileConfig );
|
||
|
}
|
||
|
|
||
|
if( !fAbort && Ctxt->fExport == FALSE ) {
|
||
|
//
|
||
|
// Also reconcile local server
|
||
|
//
|
||
|
|
||
|
ReconcileLocalService( Subnets, nSubnets );
|
||
|
}
|
||
|
|
||
|
CloseTextFile( Ctxt->hFile, Ctxt->Mem );
|
||
|
|
||
|
//
|
||
|
// Walk through the array and free up pointers
|
||
|
//
|
||
|
|
||
|
for( i = 0 ; i < Ctxt->nScopes ; i ++ ) {
|
||
|
if( Ctxt->Scopes[i].SubnetName ) {
|
||
|
LocalFree( Ctxt->Scopes[i].SubnetName );
|
||
|
}
|
||
|
}
|
||
|
if( Ctxt->Scopes ) LocalFree( Ctxt->Scopes );
|
||
|
Ctxt->Scopes = NULL; Ctxt->nScopes = 0;
|
||
|
|
||
|
if( !fAbort && Ctxt->fExport && Ctxt->fDisableExportedScopes ) {
|
||
|
//
|
||
|
// Fix the local scopes to all be disabled
|
||
|
//
|
||
|
|
||
|
DisableLocalScopes(Subnets, nSubnets);
|
||
|
}
|
||
|
|
||
|
if( NULL != Subnets && 0 != nSubnets ) {
|
||
|
LocalFree( Subnets );
|
||
|
}
|
||
|
return Error;
|
||
|
|
||
|
}
|
||
|
|