windows-nt/Source/XPSP1/NT/net/dhcp/server/exim/main.c

1125 lines
24 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}