//================================================================================ // 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 #include #include #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 ); 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); 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 ); // 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); 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 ); 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) : MemServerAddMScope(Server, Subnet); 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; } 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); 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 ); 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 ); 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; #if 0 Error = DhcpRegGetThisServer(&Hdl); if( NO_ERROR != Error ) return Error; if( Scope->fSubnet ) { Error = DhcpRegServerGetSubnetHdl( &Hdl, ConvertAddressToLPWSTR( Scope->Address, SubnetStr), &Hdl1); } else { Error = DhcpRegServerGetMScopeHdl( &Hdl, Scope->Name, &Hdl1 ); } DhcpRegCloseHdl( &Hdl ); if( NO_ERROR != Error ) return Error; #endif 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 // #if 0 Error = DhcpRegSubnetGetRangeHdl( &Hdl1, ConvertAddressToLPWSTR( Range->Start, SubnetStr ), &Hdl ); if( NO_ERROR != Error ) break; Error = DhcpRegpFillBitmasks( Hdl.Key, Range, Scope ); DhcpRegCloseHdl( &Hdl ); if( NO_ERROR != Error ) break; #else Error = DhcpRegpFillBitmasks( NULL, Range, Scope ); ASSERT( NO_ERROR == Error ); #endif Error = MemArrayNextLoc( &Scope->Ranges, &Loc ); } #if 0 DhcpRegCloseHdl( &Hdl1 ); #endif 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 //================================================================================