Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1615 lines
47 KiB

//================================================================================
// Copyright (C) 1997 Microsoft Corporation
// Author: RameshV
// Description: This implements the init time reading in of the registry
// (this may/may work even when used to read at any other time.. but is not efficient)
//================================================================================
#include <mmregpch.h>
#include <regutil.h>
#include <regsave.h>
#include "server\uniqid.h"
#define InitArray(X) do{DWORD Error = MemArrayInit((X)); Require(ERROR_SUCCESS == Error); }while(0)
#define ERRCHK do{if( ERROR_SUCCESS != Error ) goto Cleanup; }while(0)
#define FreeArray1(X) Error = LoopThruArray((X), DestroyString, NULL, NULL);Require(ERROR_SUCCESS == Error);
#define FreeArray2(X) Error = MemArrayCleanup((X)); Require(ERROR_SUCCESS == Error);
#define FreeArray(X) do{ DWORD Error; FreeArray1(X); FreeArray2(X); }while(0)
#if DBG
#define Report(Who) if(Error) DbgPrint("[DHCPServer] %s: %ld [0x%lx]\n", Who, Error, Error)
#define INVALID_REG DbgPrint
#else
#define Report(Who)
#define INVALID_REG (void)
#endif
typedef DWORD (*ARRAY_FN)(PREG_HANDLE, LPWSTR ArrayString, LPVOID MemObject);
DWORD
LoopThruArray(
IN PARRAY Array,
IN ARRAY_FN ArrayFn,
IN PREG_HANDLE Hdl,
IN LPVOID MemObject
)
{
DWORD Error;
ARRAY_LOCATION Loc;
LPWSTR ArrayString;
Error = MemArrayInitLoc(Array, &Loc);
while(ERROR_FILE_NOT_FOUND != Error) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(Array, &Loc, (LPVOID *)&ArrayString);
Require(ERROR_SUCCESS == Error && ArrayString);
Error = ArrayFn(Hdl, ArrayString, MemObject);
if( ERROR_SUCCESS != Error ) {
//
// Operation failed -- but ignore it.
//
// return Error;
}
Error = MemArrayNextLoc(Array, &Loc);
}
return ERROR_SUCCESS;
}
DWORD
DestroyString(
IN PREG_HANDLE Unused,
IN LPWSTR StringToFree,
IN LPVOID Unused2
)
{
MemFree(StringToFree);
return ERROR_SUCCESS;
}
DWORD
WStringToAddress(
IN LPWSTR Str
)
{
CHAR IpString[100];
DWORD Count;
Count = wcstombs(IpString, Str, sizeof(IpString)-1);
if( -1 == Count ) return 0;
return htonl(inet_addr(IpString));
}
DWORD
ConvertWStringToDWORD(
IN LPWSTR Str
)
{
return _wtoi(Str);
}
DWORD
DhcpRegpSubnetAddServer(
IN PREG_HANDLE Hdl,
IN LPWSTR ServerName,
IN PM_SUBNET Subnet
)
{
return ERROR_SUCCESS;
}
DWORD
SetBitForRange(
IN PM_RANGE Range,
IN DWORD Address
)
{
BOOL WasSet;
if( Address > Range->End || Address < Range->Start )
return ERROR_INVALID_PARAMETER;
return MemBitSetOrClear(
Range->BitMask,
Address - Range->Start,
TRUE,
&WasSet
);
}
DWORD GlobalWorkingOnOldStyleSubnet = 0;
DWORD GlobalWorkingOnPreWin2kMScope = 0;
const DWORD One = 0x1;
DWORD
DhcpRegFillClusterAddresses(
IN OUT PM_RANGE Range,
IN LPBYTE InUseClusters,
IN DWORD InUseClustersSize,
IN LPBYTE UsedClusters,
IN DWORD UsedClustersSize
) {
DWORD Error;
DWORD i;
DWORD Address;
DWORD UNALIGNED* InUseBits;
DWORD UNALIGNED* UsedBits;
DWORD nInUseBits;
DWORD nUsedBits;
if( InUseClusters && InUseClustersSize ) {
nInUseBits = InUseClustersSize/sizeof(DWORD);
InUseBits = (DWORD UNALIGNED*)InUseClusters;
Require(nInUseBits == 2*InUseBits[0] + 1 );
nInUseBits --; InUseBits ++;
while(nInUseBits) {
for(i = 0; i < sizeof(DWORD)*8; i ++ )
if( InUseBits[1] & ( One << i ) )
SetBitForRange(Range, InUseBits[0] + i );
nInUseBits -= 2;
InUseBits += 2;
}
}
if( UsedClusters && UsedClustersSize ) {
nUsedBits = UsedClustersSize/sizeof(DWORD);
UsedBits = (DWORD UNALIGNED*)UsedClusters;
Require(nUsedBits == UsedBits[0] + 1);
nUsedBits --; UsedBits ++;
while(nUsedBits) {
for( i = 0; i < sizeof(DWORD)*8; i ++ )
SetBitForRange(Range, UsedBits[0] + i);
UsedBits ++;
nUsedBits --;
}
}
return ERROR_SUCCESS;
}
static DWORD Masks[] = {
0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
};
DWORD
DhcpRegpFillBitsForRange(
IN LPBYTE Buffer,
IN ULONG BufSize,
IN OUT PM_RANGE Range,
IN PM_SUBNET Subnet
)
{
ULONG Size, AllocSize, nSet, Offset;
ULONG nBitsSet, Index;
ULONG Error;
Size = ntohl(((UNALIGNED DWORD *)Buffer)[0]);
AllocSize = ntohl(((UNALIGNED DWORD *)Buffer)[1]);
nSet = ntohl(((UNALIGNED DWORD *)Buffer)[2]);
Offset = ntohl(((UNALIGNED DWORD *)Buffer)[3]);
//
// do not check for validity of the offset sizes.
// SetBitForRange does this check anyway.
//
// if( Range->Start + Offset + Size > 1+Range->End )
// return ERROR_INVALID_DATA;
Require(nSet != 0);
if( nSet == 0 ) return ERROR_SUCCESS;
if( nSet == Size ) {
Require( AllocSize == 0 );
for( Index = 0; Index < nSet ; Index ++ ) {
Error = SetBitForRange(Range, Range->Start + Index);
Require( ERROR_SUCCESS == Error );
}
return ERROR_SUCCESS;
}
if( AllocSize + sizeof(DWORD)*4 != BufSize ) return ERROR_INVALID_DATA;
nBitsSet = 0;
Require( Size/8 <= AllocSize );
for( Index = 0; Index < Size ; Index ++ ) {
if( Buffer[ 4*sizeof(DWORD) + (Index/8) ] & Masks[Index%8] ) {
nBitsSet ++;
//
// whistler bug 283457, offset not taken into account
//
Error = SetBitForRange( Range, Range->Start + Index + Offset );
Require( ERROR_SUCCESS == Error );
}
}
Require(nBitsSet == nSet);
return ERROR_SUCCESS;
}
static
BYTE TempBuffer[MAX_BIT1SIZE + sizeof(DWORD)*4];
DWORD
DhcpRegpFillBitmasks(
IN HKEY Key,
IN PM_RANGE Range,
IN PM_SUBNET Subnet
)
{
ULONG Error, nValues, Index;
WCHAR ValueNameBuf[100];
DWORD ValueNameSize, ValueType;
DWORD ValueSize;
WCHAR RangeStartStr[30];
BOOL fPostNt5 = FALSE;
REG_HANDLE Hdl;
if( NULL == Key ) {
ConvertAddressToLPWSTR( Range->Start, RangeStartStr);
fPostNt5 = TRUE;
Error = DhcpRegGetThisServer( &Hdl );
if( NO_ERROR != Error ) return Error;
Key = Hdl.Key;
}
Error = RegQueryInfoKey(
Key, NULL, NULL, NULL, NULL, NULL, NULL, &nValues, NULL, NULL, NULL, NULL
);
if( ERROR_SUCCESS != Error ) goto Cleanup;
Index = nValues -1;
while( nValues ) {
ValueNameSize = sizeof(ValueNameBuf)/sizeof(WCHAR);
ValueSize = sizeof(TempBuffer)/sizeof(WCHAR);
Error = RegEnumValue(
Key,
Index,
ValueNameBuf,
&ValueNameSize,
NULL,
&ValueType,
TempBuffer,
&ValueSize
);
if( ERROR_SUCCESS != Error ) goto Cleanup;
if( fPostNt5 && 0 != wcsncmp(
ValueNameBuf, RangeStartStr, wcslen(RangeStartStr)) ) {
//
// Skip irrelevant bitmaps
//
Index --;
nValues --;
continue;
}
if( REG_BINARY == ValueType && ValueSize >= sizeof(DWORD)*4 ) {
Error = DhcpRegpFillBitsForRange(
TempBuffer,
ValueSize,
Range,
Subnet
);
if( ERROR_SUCCESS != Error ) {
Require(FALSE);
goto Cleanup;
}
}
Index --;
nValues --;
}
Cleanup:
if( fPostNt5 ) {
DhcpRegCloseHdl( &Hdl );
}
return Error;
}
DWORD
DhcpRegpSubnetAddRange(
IN PREG_HANDLE Hdl,
IN LPWSTR RangeName,
IN PM_SUBNET Subnet
)
{
DWORD LocalError;
DWORD Error;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comment = NULL;
DWORD Flags;
DWORD StartAddress;
DWORD EndAddress;
LPBYTE InUseClusters = NULL;
DWORD InUseClustersSize;
LPBYTE UsedClusters = NULL;
DWORD UsedClustersSize;
ULONG Alloc, MaxAlloc;
PM_RANGE OverlappingRange;
PM_RANGE ThisRange = NULL;
BOOL fRangeAdded = FALSE;
Error = DhcpRegSubnetGetRangeHdl(Hdl, RangeName, &Hdl2);
if( ERROR_SUCCESS != Error ) return Error;
Error = DhcpRegRangeGetAttributes(
&Hdl2,
&Name,
&Comment,
&Flags,
&Alloc,
&MaxAlloc,
&StartAddress,
&EndAddress,
&InUseClusters,
&InUseClustersSize,
&UsedClusters,
&UsedClustersSize
);
ERRCHK;
if( 0 == StartAddress || 0 == EndAddress ) {
INVALID_REG("[DHCPServer] Noticed undefined range: %ws (ignored)\n", RangeName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
if( FALSE == Subnet->fSubnet && GlobalWorkingOnPreWin2kMScope ) {
Subnet->MScopeId = StartAddress;
GlobalWorkingOnPreWin2kMScope = FALSE;
}
Error = MemSubnetAddRange(
Subnet,
StartAddress,
EndAddress,
Flags,
Alloc,
MaxAlloc,
&OverlappingRange,
INVALID_UNIQ_ID
);
ERRCHK;
fRangeAdded = TRUE;
Error = MemSubnetGetAddressInfo(
Subnet,
StartAddress,
&ThisRange,
NULL,
NULL
);
ERRCHK;
if( InUseClustersSize || UsedClustersSize ) {
//
// Old style information? Save it as new style
//
GlobalWorkingOnOldStyleSubnet ++;
DhcpRegFillClusterAddresses(
ThisRange,
InUseClusters,
InUseClustersSize,
UsedClusters,
UsedClustersSize
); // this is always returning ERROR_SUCCESS.
//
// Error = FlushRanges(ThisRange, FLUSH_ANYWAY, Subnet);
// Require( ERROR_SUCCESS == Error );
//
// Do not actually write back the stuff to the registry..
// This read code path is used in dhcpexim at which time
// the registry should not be munged..
//
} else {
//
// Need to read new style bitmasks..
//
Error = DhcpRegpFillBitmasks(
Hdl2.Key,
ThisRange,
Subnet
);
Require( ERROR_SUCCESS == Error );
}
Cleanup:
Report("SubnetAddRange");
if( ERROR_SUCCESS != Error && ThisRange ) {
if( !fRangeAdded ) {
LocalError = MemRangeCleanup(ThisRange);
Require( ERROR_SUCCESS == LocalError );
} else {
LocalError = MemSubnetDelRange(
Subnet, StartAddress );
Require( ERROR_SUCCESS == LocalError );
}
}
if( Name ) MemFree(Name);
if( Comment ) MemFree(Comment);
if( InUseClusters ) MemFree(InUseClusters);
if( UsedClusters ) MemFree(UsedClusters);
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
return Error;
}
DWORD
DhcpRegpReservationAddOption(
IN PREG_HANDLE Hdl,
IN LPWSTR OptionName,
IN PM_RESERVATION Reservation
)
{
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
DWORD OptionId;
LPWSTR ClassName = NULL;
LPWSTR VendorName = NULL;
DWORD Flags;
LPBYTE Value = NULL;
DWORD ValueSize;
DWORD ClassId;
DWORD VendorId;
PM_OPTION Option = NULL;
PM_OPTION DeletedOption = NULL;
PM_CLASSDEF ThisClasDef;
Error = DhcpRegReservationGetOptHdl(Hdl, OptionName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegOptGetAttributes(
&Hdl2,
&OptionId,
&ClassName,
&VendorName,
&Flags,
&Value,
&ValueSize
);
ERRCHK;
if( OptionId == 0 ) // old registry format does not contain "OptionId" value => it can be taken from the key name.
OptionId = _wtol(OptionName);
if( OptionId == 0 || NULL == Value || 0 == ValueSize ) {
INVALID_REG("[DHCPServer] Found invalid option %ws (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
if( NULL == ClassName || wcslen(ClassName) == 0) ClassId = 0;
else {
PM_SUBNET Subnet = Reservation->SubnetPtr;
PM_SERVER Server = Subnet->ServerPtr;
Error = MemServerGetClassDef(Server,0, ClassName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
if (*(DWORD *)ClassName != OptionId) // some registry entries were corrupted due to an old bug. Load these entries too (see bug #192933)
{
INVALID_REG("ReservationAddOption(%ws): unknown class (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
else
{
ClassId = 0;
}
} else {
ClassId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == FALSE);
}
}
if( NULL == VendorName || wcslen(VendorName) == 0 ) VendorId = 0;
else {
PM_SUBNET Subnet = Reservation->SubnetPtr;
PM_SERVER Server = Subnet->ServerPtr;
Error = MemServerGetClassDef(Server,0, VendorName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
INVALID_REG("ReservationAddOption(%ws): unknown vendor (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
} else {
VendorId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == TRUE);
}
}
if( 0 == OptionId ) OptionId = ConvertWStringToDWORD(OptionName);
Error = MemOptInit(&Option, OptionId, ValueSize, Value);
ERRCHK;
Error = MemOptClassAddOption( &(Reservation->Options), Option, ClassId,
VendorId, &DeletedOption, INVALID_UNIQ_ID );
ERRCHK;
Cleanup:
Report("ReservationAddOption");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( ClassName ) MemFree(ClassName);
if( VendorName ) MemFree(VendorName);
if( Value ) MemFree(Value);
if( DeletedOption ) {
LocalError = MemOptCleanup(DeletedOption);
Require(ERROR_SUCCESS == LocalError);
}
if( ERROR_SUCCESS != Error && Option ) {
LocalError = MemOptCleanup(Option);
Require(ERROR_SUCCESS == LocalError);
}
return Error;
}
DWORD
DhcpRegpSubnetAddReservation(
IN PREG_HANDLE Hdl,
IN LPWSTR ReservationName,
IN PM_SUBNET Subnet
)
{
DWORD LocalError;
DWORD Error;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comment = NULL;
DWORD Flags;
DWORD Address;
LPBYTE ClientUID = NULL;
DWORD ClientUIDSize;
PM_RESERVATION ThisReservation;
ARRAY Options;
Error = DhcpRegSubnetGetReservationHdl(Hdl, ReservationName, &Hdl2);
if( ERROR_SUCCESS != Error ) return Error;
Error = DhcpRegReservationGetAttributes(
&Hdl2,
&Name,
&Comment,
&Flags,
&Address,
&ClientUID,
&ClientUIDSize
);
ERRCHK;
if( 0 == Address || NULL == ClientUID || 0 == ClientUIDSize ) {
INVALID_REG("[DHCPServer] Found invalid reservation %ws (ignored)\n", ReservationName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
Error = MemReserveAdd(
&(Subnet->Reservations),
Address,
Flags,
ClientUID,
ClientUIDSize,
INVALID_UNIQ_ID
);
// if the reservation is a duplicate ignore the error and do no further processing as the
// reservation structure was already initialized. The duplicate reservation will simply be
// ignored.
if (ERROR_SUCCESS == Error)
{
Error = MemReserveFindByAddress(
&(Subnet->Reservations),
Address,
&ThisReservation
);
ERRCHK;
ThisReservation->SubnetPtr = Subnet;
Error = MemArrayInit(&Options);
ERRCHK;
Error = DhcpRegReservationGetList(
&Hdl2,
&Options
);
ERRCHK;
Error = LoopThruArray(&Options, DhcpRegpReservationAddOption, &Hdl2, ThisReservation);
} else if ( ERROR_OBJECT_ALREADY_EXISTS == Error )
Error = ERROR_SUCCESS;
Cleanup:
Report("SubnetAddReservation");
if( Name ) MemFree(Name);
if( Comment ) MemFree(Comment);
if( ClientUID ) MemFree(ClientUID);
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
FreeArray(&Options);
return Error;
}
DWORD
DhcpRegpSubnetAddOption(
IN PREG_HANDLE Hdl,
IN LPWSTR OptionName,
IN PM_SUBNET Subnet
)
{
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
DWORD OptionId;
LPWSTR ClassName = NULL;
LPWSTR VendorName = NULL;
DWORD Flags;
LPBYTE Value = NULL;
DWORD ValueSize;
DWORD ClassId;
DWORD VendorId;
PM_OPTION Option = NULL;
PM_OPTION DeletedOption = NULL;
PM_CLASSDEF ThisClasDef;
Error = DhcpRegSubnetGetOptHdl(Hdl, OptionName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegOptGetAttributes(
&Hdl2,
&OptionId,
&ClassName,
&VendorName,
&Flags,
&Value,
&ValueSize
);
ERRCHK;
if( OptionId == 0 ) // old registry format does not contain "OptionId" value => it can be taken from the key name.
OptionId = _wtol(OptionName);
if( OptionId == 0 || NULL == Value || 0 == ValueSize ) {
INVALID_REG("[DHCPServer] Found invalid option %ws (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
if( NULL == ClassName || wcslen(ClassName) == 0) ClassId = 0;
else {
Error = MemServerGetClassDef((PM_SERVER)(Subnet->ServerPtr),0, ClassName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
if (*(DWORD *)ClassName != OptionId) // some registry entries were corrupted due to an old bug. Load these entries too (see bug #192933)
{
INVALID_REG("SubnetAddOption(%ws): unknown class (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
else
{
ClassId = 0;
}
} else {
ClassId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == FALSE);
}
}
if( NULL == VendorName || wcslen(VendorName) == 0 ) VendorId = 0;
else {
Error = MemServerGetClassDef((PM_SERVER)(Subnet->ServerPtr),0, VendorName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
INVALID_REG("SubnetAddOption(%ws): unknown class (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
} else {
VendorId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == TRUE);
}
}
if( 0 == OptionId ) OptionId = ConvertWStringToDWORD(OptionName);
Error = MemOptInit(&Option, OptionId, ValueSize, Value);
ERRCHK;
Error = MemOptClassAddOption( &(Subnet->Options), Option, ClassId,
VendorId, &DeletedOption, INVALID_UNIQ_ID );
ERRCHK;
Cleanup:
Report("Subnet Add Option");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( ClassName ) MemFree(ClassName);
if( VendorName ) MemFree(VendorName);
if( Value ) MemFree(Value);
if( DeletedOption ) {
LocalError = MemOptCleanup(DeletedOption);
Require(ERROR_SUCCESS == LocalError);
}
if( ERROR_SUCCESS != Error && Option ) {
LocalError = MemOptCleanup(Option);
Require(ERROR_SUCCESS == LocalError);
}
return Error;
}
DWORD
DhcpRegSubnetAddExclusions(
IN PM_SUBNET Subnet,
IN LPBYTE Excl,
IN DWORD ExclSize
)
{
DWORD UNALIGNED* Addr;
DWORD Count, i, j;
DWORD Error;
PM_EXCL OverlappingExcl;
Count = ExclSize / sizeof(DWORD);
Addr = (DWORD UNALIGNED*)Excl;
if( 0 == Count || 0 == Addr[0] || 0 == Addr[1] ) {
INVALID_REG("[DHCPServer] invalid exclusion ignored\n");
return ERROR_SUCCESS;
}
Require(Count == 2*Addr[0] + 1);
Count --; Addr ++;
while(Count) {
Error = MemSubnetAddExcl(
Subnet,
Addr[0],
Addr[1],
&OverlappingExcl,
INVALID_UNIQ_ID
);
if( ERROR_SUCCESS != Error ) {
INVALID_REG("[DHCPServer] DhcpRegSubnetAddExclusions:MemSubnetAddExcl;0x%lx\n", Error);
} else {
if( Subnet->fSubnet && GlobalWorkingOnOldStyleSubnet ) {
//
// For subnets alone (not mscopes), check if
// we are upgrading from pre-win2k -- then make sure
// all address from the excluded range are removed
// from the bitmask
//
for( i = Addr[0]; i <= Addr[1]; i ++ ) {
MemSubnetReleaseAddress(
Subnet, i, FALSE
);
}
}
}
Addr += 2;
Count -= 2;
}
return ERROR_SUCCESS;
}
DWORD
DhcpRegServerAddSubnet(
IN PREG_HANDLE Hdl,
IN PM_SERVER Server,
IN PM_SUBNET Subnet
)
{
DWORD Error;
DWORD Index;
ARRAY Servers;
ARRAY IpRanges;
ARRAY Reservations;
ARRAY Options;
LPBYTE Excl = NULL;
DWORD ExclSize;
struct {
PARRAY Array;
ARRAY_FN Fn;
} Lists[] = {
&Servers, DhcpRegpSubnetAddServer,
&IpRanges, DhcpRegpSubnetAddRange,
&Reservations, DhcpRegpSubnetAddReservation,
&Options, DhcpRegpSubnetAddOption
};
Subnet->ServerPtr = Server;
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
InitArray(Lists[Index].Array);
}
Error = DhcpRegSubnetGetList(
Hdl, &Servers, &IpRanges, &Reservations, &Options, &Excl, &ExclSize
);
GlobalWorkingOnOldStyleSubnet = 0;
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
Error = LoopThruArray(Lists[Index].Array, Lists[Index].Fn, Hdl, Subnet);
ERRCHK;
}
if( GlobalWorkingOnOldStyleSubnet ) {
Report("Old style subnet found, careful with exclusions\n");
}
if( Excl ) Error = DhcpRegSubnetAddExclusions(Subnet, Excl, ExclSize);
ERRCHK;
Error = Subnet->fSubnet ? MemServerAddSubnet(Server, Subnet, INVALID_UNIQ_ID )
: MemServerAddMScope(Server, Subnet, INVALID_UNIQ_ID );
Cleanup:
GlobalWorkingOnOldStyleSubnet = 0;
GlobalWorkingOnPreWin2kMScope = 0;
Report("ServerAddSubnet");
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
FreeArray(Lists[Index].Array);
}
return Error;
}
DWORD
DhcpRegServerAddMScope(
IN PREG_HANDLE Hdl,
IN PM_SERVER Server,
IN PM_MSCOPE MScope
)
{
return DhcpRegServerAddSubnet(Hdl, Server, MScope);
}
DWORD
DhcpRegServerAddSScope(
IN PREG_HANDLE Hdl,
IN PM_SERVER Server,
IN PM_SSCOPE SScope
)
{
DWORD Error;
ARRAY Subnets;
ARRAY_LOCATION Loc;
LPWSTR SubnetWString;
DWORD SubnetAddress;
PM_SUBNET Subnet;
InitArray(&Subnets);
Error = DhcpRegSScopeGetList(Hdl, &Subnets);
ERRCHK;
Error = MemArrayInitLoc(&Subnets, &Loc);
while(ERROR_FILE_NOT_FOUND != Error) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnets, &Loc, &SubnetWString);
Require(ERROR_SUCCESS == Error && SubnetWString);
SubnetAddress = WStringToAddress(SubnetWString);
Error = MemServerGetAddressInfo(
Server,
SubnetAddress,
&Subnet,
NULL,
NULL,
NULL
);
if( ERROR_SUCCESS == Error && Subnet ) {
Error = MemSubnetSetSuperScope(Subnet,SScope);
Require(ERROR_SUCCESS == Error);
}
Error = MemArrayNextLoc(&Subnets, &Loc);
}
Error = MemServerAddSScope( Server, SScope );
Cleanup:
Report("ServerAddSScope");
FreeArray(&Subnets);
return Error;
} // DhcpRegpServerAddSScope()
DWORD
DhcpRegpServerAddSubnet(
IN PREG_HANDLE Hdl,
IN LPWSTR SubnetName,
IN PM_SERVER Server
)
{
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comment = NULL;
DWORD Address;
DWORD Flags;
DWORD Mask;
PM_SUBNET Subnet = NULL;
Error = DhcpRegServerGetSubnetHdl(Hdl, SubnetName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegSubnetGetAttributes(
&Hdl2,
&Name,
&Comment,
&Flags,
&Address,
&Mask
);
ERRCHK;
if( NULL == Name || 0 == Address || 0 == Mask ) {
INVALID_REG("[DHCPServer] invalid subnet %ws ignored\n", SubnetName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
Error = MemSubnetInit(
&Subnet,
Address,
Mask,
Flags,
0,
Name,
Comment
);
ERRCHK;
Error = DhcpRegServerAddSubnet(&Hdl2, Server, Subnet);
Cleanup:
Report("ServerAddSubnet");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require( ERROR_SUCCESS == LocalError);
if( Name ) MemFree(Name);
if( Comment ) MemFree(Comment);
if( ERROR_SUCCESS != Error ) {
if( Subnet ) {
LocalError = MemSubnetCleanup(Subnet);
Require(ERROR_SUCCESS == LocalError);
}
}
return Error;
}
DWORD
DhcpRegpServerAddMScope(
IN PREG_HANDLE Hdl,
IN LPWSTR MScopeName,
IN PM_SERVER Server
) {
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
LPWSTR Comment = NULL;
DWORD State;
DWORD ScopeId;
DWORD Policy;
PM_MSCOPE MScope = NULL;
LPWSTR LangTag = NULL;
DWORD TTL = 32;
PDATE_TIME ExpiryTime = NULL;
GlobalWorkingOnPreWin2kMScope = 0;
Error = DhcpRegServerGetMScopeHdl(Hdl, MScopeName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegMScopeGetAttributes(
&Hdl2,
&Comment,
&State,
&ScopeId,
&Policy,
&TTL,
&LangTag,
&ExpiryTime
);
if( ERROR_INVALID_DATA == Error ) {
GlobalWorkingOnPreWin2kMScope = TRUE;
//
// hackorama isn't it?
//
Error = NO_ERROR;
}
ERRCHK;
if( 0 == ScopeId || GlobalWorkingOnPreWin2kMScope ) {
INVALID_REG("[DHCPServer] invalid m-scope %ws, id %ld ignored\n", MScopeName, ScopeId);
Error = ERROR_SUCCESS;
//goto Cleanup;
}
Error = MemMScopeInit(
&MScope,
ScopeId,
State,
Policy,
(BYTE)TTL,
MScopeName,
Comment,
LangTag,
*ExpiryTime
);
ERRCHK;
Error = DhcpRegServerAddMScope(&Hdl2, Server, MScope);
Cleanup:
GlobalWorkingOnPreWin2kMScope = 0;
Report("Server Add MScope");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( Comment ) MemFree(Comment);
if( LangTag ) MemFree(LangTag);
if( ExpiryTime ) MemFree(ExpiryTime);
if( ERROR_SUCCESS != Error ) {
if( MScope ) {
LocalError = MemMScopeCleanup(MScope);
Require(ERROR_SUCCESS == Error);
}
}
return Error;
}
DWORD
DhcpRegpServerAddSScope(
IN PREG_HANDLE Hdl,
IN LPWSTR SScopeName,
IN PM_SERVER Server
) {
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comment = NULL;
DWORD Flags;
PM_SSCOPE SScope = NULL;
Error = DhcpRegServerGetSScopeHdl(Hdl, SScopeName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
#if 0 // superscope name is given above -- nothing else to be done
Error = DhcpRegSScopeGetAttributes(
&Hdl2,
&Name,
&Description,
&Flags
);
ERRCHK;
#endif
Error = MemSScopeInit(
&SScope,
0,
SScopeName
);
ERRCHK;
Error = DhcpRegServerAddSScope(&Hdl2, Server, SScope);
Cleanup:
Report("Server Add Scope");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( ERROR_SUCCESS != Error ) {
if( SScope ) {
LocalError = MemSScopeCleanup(SScope);
Require(ERROR_SUCCESS == Error);
}
}
return Error;
}
DWORD
DhcpRegpServerAddOption(
IN PREG_HANDLE Hdl,
IN LPWSTR OptionName,
IN PM_SERVER Server
) {
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
DWORD OptionId;
LPWSTR ClassName = NULL;
LPWSTR VendorName = NULL;
DWORD Flags;
LPBYTE Value = NULL;
DWORD ValueSize;
DWORD ClassId;
DWORD VendorId;
PM_OPTION Option = NULL;
PM_OPTION DeletedOption = NULL;
PM_CLASSDEF ThisClasDef;
Error = DhcpRegServerGetOptHdl(Hdl, OptionName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegOptGetAttributes(
&Hdl2,
&OptionId,
&ClassName,
&VendorName,
&Flags,
&Value,
&ValueSize
);
ERRCHK;
if( OptionId == 0 ) // old registry format does not contain "OptionId" value => it can be taken from the key name.
OptionId = _wtol(OptionName);
if( 0 == OptionId || NULL == Value || 0 == ValueSize ) {
INVALID_REG("[DHCPServer] found invalid option %ws (ignored)\n", OptionName );
Error = ERROR_SUCCESS;
goto Cleanup;
}
if( NULL == ClassName || wcslen(ClassName) == 0) ClassId = 0;
else {
Error = MemServerGetClassDef(Server,0, ClassName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
if (*(DWORD *)ClassName != OptionId) // some registry entries were corrupted due to an old bug. Load these entries too (see bug #192933)
{
INVALID_REG("ServerAddOption(%ws): unknown class (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
else
{
ClassId = 0;
}
} else {
ClassId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == FALSE);
}
}
if( NULL == VendorName || wcslen(VendorName) == 0) VendorId = 0;
else {
Error = MemServerGetClassDef(Server,0, VendorName,0,NULL,&ThisClasDef);
if( ERROR_SUCCESS != Error ) {
INVALID_REG("ServerAddOption(%ws): unknown class (ignored)\n", OptionName);
Error = ERROR_SUCCESS;
goto Cleanup;
} else {
VendorId = ThisClasDef->ClassId;
Require(ThisClasDef->IsVendor == TRUE);
}
}
Error = MemOptInit(&Option, OptionId, ValueSize, Value);
ERRCHK;
Error = MemOptClassAddOption( &(Server->Options), Option, ClassId,
VendorId, &DeletedOption, INVALID_UNIQ_ID );
ERRCHK;
Cleanup:
Report("Server Add Option");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( ClassName ) MemFree(ClassName);
if( VendorName ) MemFree(VendorName);
if( Value ) MemFree(Value);
if( DeletedOption ) {
LocalError = MemOptCleanup(DeletedOption);
Require(ERROR_SUCCESS == LocalError);
}
if( ERROR_SUCCESS != Error && Option ) {
LocalError = MemOptCleanup(Option);
Require(ERROR_SUCCESS == LocalError);
}
return Error;
}
DWORD
DhcpRegpServerAddDefList(
IN PREG_HANDLE Hdl,
IN LPWSTR DefName,
IN PM_SERVER Server
) {
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comments = NULL;
DWORD Flags;
DWORD OptionId;
LPWSTR ClassName = NULL;
LPWSTR VendorName = NULL;
DWORD ClassId;
DWORD VendorId;
LPBYTE Value = NULL;
DWORD ValueSize;
PM_CLASSDEF ThisClassDef;
Error = DhcpRegServerGetOptDefHdl(Hdl, DefName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegOptDefGetAttributes(
&Hdl2,
&Name,
&Comments,
&Flags,
&OptionId,
&ClassName,
&VendorName,
&Value,
&ValueSize
);
ERRCHK;
if( OptionId == 0)
OptionId = _wtol(DefName);
if( NULL == Name || 0 == OptionId ) {
INVALID_REG("[DHCPServer] invalid option def %ws ignored\n", DefName );
Error = ERROR_SUCCESS;
goto Cleanup;
}
if( NULL == ClassName || wcslen(ClassName) == 0) ClassId = 0;
else {
Error = MemServerGetClassDef(Server,0, ClassName,0,NULL,&ThisClassDef);
if( ERROR_SUCCESS != Error ) ClassId = 0;
else {
ClassId = ThisClassDef->ClassId;
Require(ThisClassDef->IsVendor == FALSE);
}
}
if( NULL == VendorName || wcslen(VendorName) == 0 ) VendorId = 0;
else {
Error = MemServerGetClassDef(Server,0, VendorName,0,NULL,&ThisClassDef);
if( ERROR_SUCCESS != Error ) VendorId = 0;
else {
VendorId = ThisClassDef->ClassId;
Require(ThisClassDef->IsVendor == TRUE);
}
}
Error = MemOptClassDefListAddOptDef(
&(Server->OptDefs),
ClassId,
VendorId,
OptionId,
Flags,
Name,
Comments,
Value,
ValueSize,
INVALID_UNIQ_ID
);
Cleanup:
Report("Server Add DefList");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( Name ) MemFree(Name);
if( Comments ) MemFree(Comments);
if( ClassName ) MemFree(ClassName);
if( VendorName ) MemFree(VendorName);
if( Value ) MemFree(Value);
return Error;
}
DWORD
DhcpRegpServerAddClassDef(
IN PREG_HANDLE Hdl,
IN LPWSTR ClassDefName,
IN PM_SERVER Server
) {
DWORD Error;
DWORD LocalError;
REG_HANDLE Hdl2;
LPWSTR Name = NULL;
LPWSTR Comment = NULL;
DWORD Flags;
LPBYTE Value = NULL;
DWORD ValueSize;
Error = DhcpRegServerGetClassDefHdl(Hdl, ClassDefName, &Hdl2);
if(ERROR_SUCCESS != Error) return Error;
Error = DhcpRegClassDefGetAttributes(
&Hdl2,
&Name,
&Comment,
&Flags,
&Value,
&ValueSize
);
ERRCHK;
if( NULL == Name || 0 == ValueSize || NULL == Value ) {
INVALID_REG("[DHCPServer] invalid class def %ws ignored\n", ClassDefName);
Error = ERROR_SUCCESS;
goto Cleanup;
}
Error = MemClassDefListAddClassDef(
&(Server->ClassDefs),
MemNewClassId(),
Flags,
0, /* no Type... */
Name,
Comment,
Value,
ValueSize,
INVALID_UNIQ_ID
);
ERRCHK;
Cleanup:
Report("Server Add ClassDef");
LocalError = DhcpRegCloseHdl(&Hdl2);
Require(ERROR_SUCCESS == LocalError);
if( Name ) MemFree(Name);
if( Comment ) MemFree(Comment);
if( Value ) MemFree(Value);
return Error;
}
//BeginExport(function)
DWORD
DhcpRegReadSubServer( // read all the sub objects of a server and add 'em
IN PREG_HANDLE Hdl,
IN OUT PM_SERVER Server
) //EndExport(function)
{
DWORD Error;
DWORD Index;
ARRAY OptList;
ARRAY DefList;
ARRAY ClassDefs;
ARRAY Subnets;
ARRAY MScopes;
ARRAY SScopes;
struct {
PARRAY Array;
ARRAY_FN Fn;
} Lists[] = {
&ClassDefs, DhcpRegpServerAddClassDef,
&DefList, DhcpRegpServerAddDefList,
&OptList, DhcpRegpServerAddOption,
&Subnets, DhcpRegpServerAddSubnet,
&MScopes, DhcpRegpServerAddMScope,
&SScopes, DhcpRegpServerAddSScope
};
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
InitArray(Lists[Index].Array);
}
Error = DhcpRegServerGetList(
Hdl, &OptList, &DefList, &Subnets, &SScopes, &ClassDefs, &MScopes
);
ERRCHK;
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
Error = LoopThruArray(Lists[Index].Array, Lists[Index].Fn, Hdl, Server);
ERRCHK;
}
Cleanup:
for( Index = 0; Index < sizeof(Lists)/sizeof(Lists[0]); Index ++ ) {
FreeArray(Lists[Index].Array);
}
Report("ServerAddSubServer");
return Error;
}
//BeginExport(function)
DWORD
DhcpRegReadServer( // read the server and all its sub objects
IN PREG_HANDLE Hdl,
OUT PM_SERVER *Server // return the created object
) //EndExport(function)
{
DWORD Error;
LPWSTR Name;
LPWSTR Comments;
DWORD Flags;
PM_SERVER ThisServer;
Name = NULL; Comments = NULL; Flags = 0; ThisServer = NULL;
Error = DhcpRegServerGetAttributes(
Hdl,
&Name,
&Comments,
&Flags
);
if( ERROR_SUCCESS != Error ) goto Cleanup;
Error = MemServerInit(
&ThisServer,
0xFFFFFFFF,
Flags,
0,
Name,
Comments
);
if( ERROR_SUCCESS != Error ) goto Cleanup;
Error = DhcpRegReadSubServer(Hdl, ThisServer);
if( ERROR_SUCCESS != Error ) goto Cleanup;
*Server = ThisServer;
Cleanup:
if( NULL != Name ) MemFree(Name);
if( NULL != Comments) MemFree(Comments);
if( ERROR_SUCCESS != Error && NULL != ThisServer) {
MemServerCleanup(ThisServer);
}
return Error;
}
//BeginExport(function)
DWORD
DhcpRegReadThisServer( // recursively read for the current server
OUT PM_SERVER *Server
) //EndExport(function)
{
DWORD Error;
REG_HANDLE ThisServer;
LPWSTR Name;
LPWSTR Comment;
Error = DhcpRegGetThisServer(&ThisServer);
if( ERROR_SUCCESS != Error ) return Error;
Error = DhcpRegReadServer(&ThisServer, Server);
DhcpRegCloseHdl(&ThisServer);
return Error;
}
DWORD
DhcpRegReadScopeBitmasks(
IN OUT PM_SUBNET Scope
)
{
PM_RANGE Range;
ARRAY_LOCATION Loc;
DWORD Error;
WCHAR SubnetStr[sizeof("000.000.000.000")];
REG_HANDLE Hdl, Hdl1;
Error = MemArrayInitLoc( &Scope->Ranges, &Loc);
while( NO_ERROR == Error ) {
Error = MemArrayGetElement( &Scope->Ranges, &Loc, &Range );
Require( NO_ERROR == Error && NULL != Range );
//
// Fill in the range
//
Error = DhcpRegpFillBitmasks(
NULL, Range, Scope );
ASSERT( NO_ERROR == Error );
Error = MemArrayNextLoc( &Scope->Ranges, &Loc );
}
if( ERROR_FILE_NOT_FOUND != Error ) return Error;
return NO_ERROR;
}
//BeginExport(function)
DWORD
DhcpRegReadServerBitmasks(
IN OUT PM_SERVER Server
) // EndExport(function)
{
PM_SUBNET Scope, MScope;
ARRAY_LOCATION Loc;
DWORD Error;
Error = MemArrayInitLoc(&Server->Subnets, &Loc);
while( NO_ERROR == Error ) {
Error = MemArrayGetElement( &Server->Subnets, &Loc, &Scope);
Require( NO_ERROR == Error && NULL != Scope );
//
// get the keys to the scope in question
//
Error = DhcpRegReadScopeBitmasks(Scope);
if( NO_ERROR != Error ) return Error;
Error = MemArrayNextLoc( &Server->Subnets, &Loc );
}
if( ERROR_FILE_NOT_FOUND != Error ) return Error;
Error = MemArrayInitLoc(&Server->MScopes, &Loc);
while( NO_ERROR == Error ) {
Require( ERROR_SUCCESS == Error );
Error = MemArrayGetElement( &Server->MScopes, &Loc, &MScope);
Require( NO_ERROR == Error && NULL != MScope );
//
// get the keys to the scope in question
//
Error = DhcpRegReadScopeBitmasks(MScope);
if( NO_ERROR != Error ) return Error;
Error = MemArrayNextLoc( &Server->MScopes, &Loc );
}
if( ERROR_FILE_NOT_FOUND != Error ) return Error;
return NO_ERROR;
}
//================================================================================
// end of file
//================================================================================