windows-nt/Source/XPSP1/NT/net/dhcp/server/dhcpds/rpcapi1.c

2797 lines
111 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//================================================================================
// Copyright (C) 1997 Microsoft Corporation
// Author: RameshV
// Description: most of the rpc apis are here and some miscellaneous functions too
// all the functions here go to the DS directly.
//================================================================================
#include <hdrmacro.h>
#include <store.h>
#include <dhcpmsg.h>
#include <wchar.h>
#include <dhcpbas.h>
#include <mm\opt.h>
#include <mm\optl.h>
#include <mm\optdefl.h>
#include <mm\optclass.h>
#include <mm\classdefl.h>
#include <mm\bitmask.h>
#include <mm\reserve.h>
#include <mm\range.h>
#include <mm\subnet.h>
#include <mm\sscope.h>
#include <mm\oclassdl.h>
#include <mm\server.h>
#include <mm\address.h>
#include <mm\server2.h>
#include <mm\memfree.h>
#include <mmreg\regutil.h>
#include <mmreg\regread.h>
#include <mmreg\regsave.h>
#include <dhcpapi.h>
//================================================================================
// THE FOLLOWING FUNCTIONS HAVE BEEN COPIED OVER FROM RPCAPI1.C (IN THE
// DHCP\SERVER\SERVER DIRECTORY).
//================================================================================
#undef DhcpPrint
#define DhcpPrint(X)
#define DhcpAssert(X)
typedef struct _OPTION_BIN {
DWORD DataSize;
DHCP_OPTION_DATA_TYPE OptionType;
DWORD NumElements;
BYTE Data[0];
} OPTION_BIN, *LPOPTION_BIN;
#define IS_SPACE_AVAILABLE(FilledSize, AvailableSize, RequiredSpace ) ((FilledSize) + (RequiredSpace) <= (AvailableSize) )
BOOL _inline
CheckForVendor(
IN DWORD OptId,
IN BOOL IsVendor
)
{
if( IsVendor ) return (256 <= OptId);
return 256 > OptId;
}
DWORD _inline
ConvertOptIdToRPCValue(
IN DWORD OptId,
IN BOOL IsVendorUnused
)
{
return OptId % 256;
}
DWORD _inline
ConvertOptIdToMemValue(
IN DWORD OptId,
IN BOOL IsVendor
)
{
if( IsVendor ) return OptId + 256;
return OptId;
}
DWORD
DhcpConvertOptionRPCToRegFormat(
IN LPDHCP_OPTION_DATA Option,
IN OUT LPBYTE RegBuffer, // OPTIONAL
IN OUT DWORD *BufferSize // input: buffer size, output: filled buffer size
)
{
OPTION_BIN Dummy;
DWORD AvailableSize;
DWORD FilledSize;
DWORD nElements;
DWORD i;
DWORD DataLength;
DWORD Length;
DHCP_OPTION_DATA_TYPE OptType;
LPBYTE BufStart;
AvailableSize = *BufferSize;
FilledSize = 0;
BufStart = RegBuffer;
Dummy.DataSize = sizeof(Dummy);
Dummy.OptionType = DhcpByteOption;
Dummy.NumElements = 0;
FilledSize = ROUND_UP_COUNT(sizeof(Dummy), ALIGN_WORST);
RegBuffer += FilledSize; // will do this actual filling at the very end
if( NULL == Option || 0 == Option->NumElements ) {
OptType = DhcpByteOption;
nElements =0;
} else {
OptType = Option->Elements[0].OptionType;
nElements = Option->NumElements;
}
for( i = 0; i < nElements ; i ++ ) { // marshal each argument in
if( OptType != Option->Elements[i].OptionType ) {
return ERROR_INVALID_PARAMETER; // do not allow random option types, all got to be same
}
switch(OptType) {
case DhcpByteOption:
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, sizeof(DWORD)) ) {
*((LPDWORD)RegBuffer) = Option->Elements[i].Element.ByteOption;
RegBuffer += sizeof(DWORD);
}
FilledSize += sizeof(DWORD);
break;
case DhcpWordOption:
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, sizeof(DWORD)) ) {
*((LPDWORD)RegBuffer) = Option->Elements[i].Element.WordOption;
RegBuffer += sizeof(DWORD);
}
FilledSize += sizeof(DWORD);
break;
case DhcpDWordOption:
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, sizeof(DWORD) )) {
*((LPDWORD)RegBuffer) = Option->Elements[i].Element.DWordOption;
RegBuffer += sizeof(DWORD);
}
FilledSize += sizeof(DWORD);
break;
case DhcpDWordDWordOption:
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, sizeof(DWORD_DWORD)) ) {
*((LPDWORD_DWORD)RegBuffer) = Option->Elements[i].Element.DWordDWordOption;
RegBuffer += sizeof(DWORD);
}
FilledSize += sizeof(DWORD_DWORD);
break;
case DhcpIpAddressOption:
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, sizeof(DHCP_IP_ADDRESS)) ) {
*((LPDHCP_IP_ADDRESS)RegBuffer) = Option->Elements[i].Element.IpAddressOption;
RegBuffer += sizeof(DHCP_IP_ADDRESS);
}
FilledSize += sizeof(DHCP_IP_ADDRESS);
break;
case DhcpStringDataOption:
if( NULL == Option->Elements[i].Element.StringDataOption ) {
DataLength = ROUND_UP_COUNT((FilledSize + sizeof(DWORD) + sizeof(WCHAR)), ALIGN_DWORD);
DataLength -= FilledSize;
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, DataLength ) ) {
*(LPDWORD)RegBuffer = (DWORD) sizeof(WCHAR);
RegBuffer += sizeof(DWORD);
*(LPWSTR)RegBuffer = L'\0';
RegBuffer += ROUND_UP_COUNT(sizeof(WCHAR), ALIGN_DWORD);
DhcpAssert(sizeof(DWORD) + ROUND_UP_COUNT(sizeof(WCHAR),ALIGN_DWORD) == DataLength);
}
FilledSize += DataLength;
break;
}
Length = (1+wcslen(Option->Elements[i].Element.StringDataOption))*sizeof(WCHAR);
DataLength = ROUND_UP_COUNT((Length + FilledSize + sizeof(DWORD)), ALIGN_DWORD);
DataLength -= FilledSize;
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, DataLength) ) {
*((LPDWORD)RegBuffer) = Length;
RegBuffer += sizeof(DWORD);
memcpy(RegBuffer, Option->Elements[i].Element.StringDataOption, Length );
RegBuffer += ROUND_UP_COUNT(Length, ALIGN_DWORD);
DhcpAssert(ROUND_UP_COUNT(Length,ALIGN_DWORD) + sizeof(DWORD) == DataLength);
}
FilledSize += DataLength;
break;
case DhcpBinaryDataOption:
case DhcpEncapsulatedDataOption:
Length = Option->Elements[i].Element.BinaryDataOption.DataLength;
DataLength = ROUND_UP_COUNT((FilledSize+Length+sizeof(DWORD)), ALIGN_DWORD);
DataLength -= FilledSize;
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, DataLength) ) {
*((LPDWORD)RegBuffer) = Length;
RegBuffer += sizeof(DWORD);
memcpy(RegBuffer, Option->Elements[i].Element.BinaryDataOption.Data, Length);
Length = ROUND_UP_COUNT(Length, ALIGN_DWORD);
DhcpAssert(Length + sizeof(DWORD) == DataLength);
RegBuffer += Length;
}
FilledSize += DataLength;
break;
default:
return ERROR_INVALID_PARAMETER; // Dont support any other kind of options
}
}
// Length = ROUND_UP_COUNT(FilledSize, ALIGN_WORST);
*BufferSize = FilledSize;
if( AvailableSize < FilledSize ) return ERROR_MORE_DATA;
Dummy.NumElements = nElements;
Dummy.DataSize = *BufferSize;
Dummy.OptionType = OptType;
memcpy(BufStart, (LPBYTE)&Dummy, sizeof(Dummy));
return ERROR_SUCCESS;
}
//================================================================================
// helper routines for ds..
//================================================================================
VOID static
MemFreeFunc(
IN OUT LPVOID Memory
)
{
MemFree(Memory);
}
//DOC DhcpConvertOptionRegToRPCFormat2 converts from the registry format option
//DOC to the RPC format. Additionally, it packs the whole stuff in one buffer.
//DOC If the Option buffer size (in bytes) as specified for input, is insufficient
//DOC to hold all the data, then, the function returns ERROR_MORE_DATA and sets
//DOC the same Size parameter to hold the actual # of bytes space required.
//DOC On a successful conversion, Size holds the total # of bytes copied.
//DOC Most of the code is same as for DhcpConvertOptionRegToRPCFormat
//DOC
DWORD
DhcpConvertOptionRegToRPCFormat2( // convert from Reg fmt to RPC..
IN LPBYTE Buffer, // reg fmt option buffer
IN DWORD BufferSize, // size of above in bytes
IN OUT LPDHCP_OPTION_DATA Option, // where to fill the option data
IN OUT LPBYTE OptBuf, // buffer for internal option data..
IN OUT DWORD *Size // i/p: sizeof(Option) o/p: reqd size
)
{
LPOPTION_BIN OptBin;
LPBYTE OptData;
LPBYTE DataBuffer;
DWORD OptSize;
DWORD OptType;
DWORD nElements;
DWORD i;
DWORD NetworkULong;
DWORD DataLength;
DWORD FilledSize;
DWORD AvailableSize;
WORD NetworkUShort;
LPDHCP_OPTION_DATA_ELEMENT Elements;
if( !Buffer || !BufferSize || !Size ) return ERROR_INVALID_PARAMETER;
AvailableSize = *Size;
FilledSize = *Size = 0;
OptBin = (LPOPTION_BIN)Buffer;
if(OptBin->DataSize != BufferSize) { // internal error!
DhcpPrint((DEBUG_ERRORS, "Internal error while parsing options\n"));
DhcpAssert(FALSE);
return ERROR_INVALID_PARAMETER;
}
OptType = OptBin->OptionType; // copy highly used stuff
nElements = OptBin->NumElements;
OptData = OptBin->Data;
OptData = ROUND_UP_COUNT(sizeof(OPTION_BIN), ALIGN_WORST) + (LPBYTE)OptBin;
if( Option ) {
Option->NumElements = 0;
Option->Elements = NULL;
}
if( 0 == nElements ) {
return ERROR_SUCCESS;
}
Elements = (LPVOID)OptBuf;
FilledSize += nElements * ROUND_UP_COUNT(sizeof(DHCP_OPTION_DATA_ELEMENT), ALIGN_WORST);
if( !IS_SPACE_AVAILABLE(FilledSize, AvailableSize, 0 ) ) {
Elements = NULL; // not enough space is really available..
}
for(i = 0; i < nElements ; i ++ ) { // marshal the elements in the data buffer
if( Elements ) { // copy only when space is there
Elements[i].OptionType = OptType;
}
switch( OptType ) { // each type has diff fields to look at
case DhcpByteOption:
if( Elements ) {
Elements[i].Element.ByteOption = *((LPBYTE)OptData);
}
OptData += sizeof(DWORD);
break;
case DhcpWordOption:
if( Elements ) {
Elements[i].Element.WordOption = (WORD)(*((LPDWORD)OptData));
}
OptData += sizeof(DWORD);
break;
case DhcpDWordOption:
if( Elements ) {
Elements[i].Element.DWordOption = *((LPDWORD)OptData);
}
OptData += sizeof(DWORD);
break;
case DhcpDWordDWordOption:
if( Elements ) {
Elements[i].Element.DWordDWordOption = *((LPDWORD_DWORD)OptData);
}
OptData += sizeof(DWORD_DWORD);
break;
case DhcpIpAddressOption:
if( Elements ) {
Elements[i].Element.IpAddressOption = *((LPDHCP_IP_ADDRESS)OptData);
}
OptData += sizeof(DHCP_IP_ADDRESS);
break;
case DhcpStringDataOption:
case DhcpBinaryDataOption:
case DhcpEncapsulatedDataOption:
DataLength = *((LPWORD)OptData);
OptData += sizeof(DWORD);
if( IS_SPACE_AVAILABLE(FilledSize, AvailableSize, DataLength) ) {
DataBuffer = (LPVOID)(FilledSize + OptBuf);
} else {
DataBuffer = NULL;
}
FilledSize += DataLength;
if( DataBuffer ) {
RtlCopyMemory( DataBuffer, OptData, DataLength );
}
OptData += ROUND_UP_COUNT(DataLength, ALIGN_DWORD);
if( Elements ) {
if( OptType == DhcpStringDataOption ) {
Elements[i].Element.StringDataOption = (LPWSTR)DataBuffer;
} else {
Elements[i].Element.BinaryDataOption.DataLength = DataLength;
Elements[i].Element.BinaryDataOption.Data = DataBuffer;
}
}
DhcpAssert( i == 0 ); // should not be more than one binary element specified
if( i > 0 ) {
DhcpPrint(( DEBUG_OPTIONS, "Multiple Binary option packed\n"));
}
break;
default:
DhcpPrint(( DEBUG_OPTIONS, "Unknown option found\n"));
break;
}
}
if( Option ) {
Option->NumElements = i; // nElements maybe?
Option->Elements = Elements;
}
*Size = FilledSize;
if( FilledSize <= AvailableSize ) return ERROR_SUCCESS;
return ERROR_MORE_DATA; // did not copy everything actually.
}
//================================================================================
// DS Access Routines
//================================================================================
//BeginExport(function)
//DOC DhcpDsCreateOptionDef tries to create an option definition in the DS with the
//DOC given attributes. The option must not exist in the DS prior to this call.
//DOC There are requirements on the fmt used in the DS.
DWORD
DhcpDsCreateOptionDef( // create option definition
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR Name, // option name
IN LPWSTR Comment, // OPTIONAL option comment
IN LPWSTR ClassName, // OPTIONAL unused, opt class
IN DWORD OptId, // # between 0-255 per DHCP draft
IN DWORD OptType, // some option flags
IN LPBYTE OptVal, // default option value
IN DWORD OptLen // # of bytes of above
) //EndExport(function)
{
DWORD Result, unused;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // mismatch
}
if( ClassName ) { // need to check class name
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ThisAttrib->String3, ClassName) ) continue;
}
Result = ERROR_DDS_OPTION_ALREADY_EXISTS;
goto Cleanup;
}
}
NothingPresent(&DummyAttrib); // prepare an elt to add to list
STRING1_PRESENT(&DummyAttrib);
if( Comment ) STRING2_PRESENT(&DummyAttrib);
if( ClassName ) STRING3_PRESENT(&DummyAttrib);
DWORD1_PRESENT(&DummyAttrib);
BINARY1_PRESENT(&DummyAttrib);
FLAGS1_PRESENT(&DummyAttrib);
DummyAttrib.String1 = Name; // fill in reqd fields only
if( Comment ) DummyAttrib.String2 = Comment;
if( ClassName ) DummyAttrib.String3 = ClassName;
DummyAttrib.Dword1 = OptId;
DummyAttrib.Flags1 = OptType;
DummyAttrib.Binary1 = OptVal;
DummyAttrib.BinLen1 = OptLen;
Result = MemArrayAddElement(&OptDefAttribs, &DummyAttrib);
if( ERROR_SUCCESS != Result ) goto Cleanup; // Add dummy element to list
Result = DhcpDsSetLists( // set the new list in DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* ClassDescriptio.. */ NULL,
/* Classes */ NULL
);
(void)MemArrayLastLoc(&OptDefAttribs, &Loc); // clear up list to way it was
//- ERROR_SUCCESS == Result
(void)MemArrayDelElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && ThisAttrib == &DummyAttrib
Cleanup: // free up any memory used
(void)MemArrayFree(&OptDefAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsModifyOptionDef tries to modify an existing optdef in the DS with the
//DOC given attributes. The option must exist in the DS prior to this call.
//DOC There are requirements on the fmt used in the DS.
DWORD
DhcpDsModifyOptionDef( // modify option definition
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR Name, // option name
IN LPWSTR Comment, // OPTIONAL option comment
IN LPWSTR ClassName, // OPTIONAL unused, opt class
IN DWORD OptId, // # between 0-255 per DHCP draft
IN DWORD OptType, // some option flags
IN LPBYTE OptVal, // default option value
IN DWORD OptLen // # of bytes of above
) //EndExport(function)
{
DWORD Result, unused;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // mismatch
}
if( ClassName ) { // need to check class name
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ThisAttrib->String3, ClassName) ) continue;
}
Result = MemArrayDelElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result
MemFreeFunc(ThisAttrib);
Result = ERROR_SUCCESS;
break;
}
}
if( ERROR_SUCCESS != Result ) { // option def was not found
Result = ERROR_DDS_OPTION_DOES_NOT_EXIST;
}
NothingPresent(&DummyAttrib); // prepare an elt to add to list
STRING1_PRESENT(&DummyAttrib);
if( Comment ) STRING2_PRESENT(&DummyAttrib);
if( ClassName ) STRING3_PRESENT(&DummyAttrib);
DWORD1_PRESENT(&DummyAttrib);
BINARY1_PRESENT(&DummyAttrib);
FLAGS1_PRESENT(&DummyAttrib);
DummyAttrib.String1 = Name; // fill in reqd fields only
if( Comment ) DummyAttrib.String2 = Comment;
if( ClassName )DummyAttrib.String3 = ClassName;
DummyAttrib.Dword1 = OptId;
DummyAttrib.Flags1 = OptType;
DummyAttrib.Binary1 = OptVal;
DummyAttrib.BinLen1 = OptLen;
Result = MemArrayAddElement(&OptDefAttribs, &DummyAttrib);
if( ERROR_SUCCESS != Result ) goto Cleanup; // Add dummy element to list
Result = DhcpDsSetLists( // set the new list in DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* ClassDescriptio.. */ NULL,
/* Classes */ NULL
);
(void)MemArrayLastLoc(&OptDefAttribs, &Loc); // clear up list to way it was
//- ERROR_SUCCESS == Result
(void)MemArrayDelElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && ThisAttrib == &DummyAttrib
Cleanup: // free up any memory used
(void)MemArrayFree(&OptDefAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsEnumOptionDefs gets the list of options defined for the given class.
//DOC Currently, class is ignored as option defs dont have classes associated.
//DOC There are requirements on the fmt used in the DS.
DWORD
DhcpDsEnumOptionDefs( // enum list of opt defs in DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // OPTIONAL, unused.
IN BOOL IsVendor, // vendor only? non-vendor only?
OUT LPDHCP_OPTION_ARRAY *RetOptArray // allocated and fill this.
) //EndExport(function)
{
DWORD Result, Result2, unused, Size, Size2, i, AllocSize;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
LPDHCP_OPTION_ARRAY OptArray;
LPBYTE Ptr;
*RetOptArray = NULL;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
Size = i = 0; // calculate size
Size += ROUND_UP_COUNT(sizeof(DHCP_OPTION_ARRAY), ALIGN_WORST);
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib)
|| !IS_DWORD1_PRESENT(ThisAttrib) ) { // invalid attrib
continue; // skip it
}
if( !CheckForVendor(ThisAttrib->Dword1, IsVendor) ) {
continue; // separate vendor and non-vendor
}
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
Size2 = 0;
Result2 = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL, // will allocate this later
/* OptBuf */ NULL,
/* Size */ &Size2
);
if( ERROR_MORE_DATA == Result2 ) Result2 = ERROR_SUCCESS;
if( ERROR_SUCCESS != Result2 ) continue; // errors? skip this attrib
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
Size2 = sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1));
if( IS_STRING2_PRESENT(ThisAttrib) ) { // if comment is present..
Size2 += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String2));
}
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
i ++;
}
Size += ROUND_UP_COUNT(i* sizeof(DHCP_OPTION), ALIGN_WORST);
Ptr = MemAlloc(AllocSize = Size);
OptArray = (LPVOID)Ptr;
if( NULL == OptArray ) return ERROR_NOT_ENOUGH_MEMORY;
Size = 0; // this time, fill in the values
Size += ROUND_UP_COUNT(sizeof(DHCP_OPTION_ARRAY), ALIGN_WORST);
Ptr += Size;
OptArray->NumElements = i;
OptArray->Options = (LPVOID)Ptr;
Size += ROUND_UP_COUNT(i* sizeof(DHCP_OPTION), ALIGN_WORST);
Ptr += ROUND_UP_COUNT(i* sizeof(DHCP_OPTION), ALIGN_WORST);
i = 0;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib)
|| !IS_DWORD1_PRESENT(ThisAttrib) ) { // invalid attrib
continue; // skip it
}
if( !CheckForVendor(ThisAttrib->Dword1, IsVendor) ) {
continue; // separate vendor and non-vendor
}
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
Size2 = AllocSize - Size;
Result2 = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &OptArray->Options[i].DefaultValue,
/* OptBuf */ Ptr,
/* Size */ &Size2
);
//- ERROR_MORE_DATA != Result2
if( ERROR_SUCCESS != Result2 ) continue; // errors? skip this attrib
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
Ptr += ROUND_UP_COUNT(Size2, ALIGN_WORST);
OptArray->Options[i].OptionID = ConvertOptIdToRPCValue(ThisAttrib->Dword1, TRUE);
if( IS_FLAGS1_PRESENT(ThisAttrib) ) { // if some flags present
OptArray->Options[i].OptionType = ThisAttrib->Flags1;
} else { // if no flags present, assume 0 type
OptArray->Options[i].OptionType = 0;
}
OptArray->Options[i].OptionName = (LPVOID)Ptr;
wcscpy((LPWSTR)Ptr, ThisAttrib->String1);
Ptr += sizeof(WCHAR)*(1+wcslen((LPWSTR)Ptr));
Size2 = sizeof(WCHAR)*(1+wcslen(ThisAttrib->String1));
if( IS_STRING2_PRESENT(ThisAttrib) ) { // if comment is present..
Size2 += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String2));
OptArray->Options[i].OptionComment = (LPVOID)Ptr;
wcscpy((LPWSTR)Ptr, ThisAttrib->String2);
} else {
OptArray->Options[i].OptionComment = NULL;
}
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
Ptr = ROUND_UP_COUNT(Size2, ALIGN_WORST) + (LPBYTE)(OptArray->Options[i].OptionName);
i ++;
}
//- OptArray->NumElements == i
*RetOptArray = OptArray;
return ERROR_SUCCESS;
}
//BeginExport(function)
//DOC DhcpDsDeleteOptionDef deletes an option definition in the DS based on the option id.
//DOC Note that the ClassName field is currently ignored.
//DOC No error is reported if the option is not present in the DS.
//DOC
DWORD
DhcpDsDeleteOptionDef( // enum list of opt defs in DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // OPTIONAL, unused.
IN DWORD OptId
) //EndExport(function)
{
DWORD Result, Result2, unused;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
Result = MemArrayDelElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result
MemFreeFunc(ThisAttrib);
Result = ERROR_SUCCESS;
break;
}
}
if( ERROR_SUCCESS != Result ) { // could not find the option in DS
Result = ERROR_SUCCESS; // pretend everything was fine
} else {
Result = DhcpDsSetLists( // set the new list in DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* ClassDescriptio.. */ NULL,
/* Classes */ NULL
);
}
(void) MemArrayFree(&OptDefAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsDeleteOptionDef deletes an option definition in the DS based on the option id.
//DOC Note that the ClassName field is currently ignored.
//DOC No error is reported if the option is not present in the DS.
//DOC
DWORD
DhcpDsGetOptionDef( // enum list of opt defs in DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // OPTIONAL, unused.
IN DWORD OptId,
OUT LPDHCP_OPTION *OptInfo
) //EndExport(function)
{
DWORD Result, Result2, unused;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
// invalid attributes?
continue;
}
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
Result = ERROR_SUCCESS;
break;
}
}
if( ERROR_SUCCESS == Result ) do {
ULONG Size, Size2;
LPBYTE Ptr;
Size2 = Size = 0;
Result = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL, // will allocate this later
/* OptBuf */ NULL,
/* Size */ &Size2
);
if( ERROR_MORE_DATA == Result ) Result = ERROR_SUCCESS;
if( ERROR_SUCCESS != Result ) break; // errors? skip this attrib
Size = ROUND_UP_COUNT(sizeof(DHCP_OPTION), ALIGN_WORST);
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1));
if( IS_STRING2_PRESENT(ThisAttrib) ) {
Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String2));
}
(*OptInfo) = (LPVOID)Ptr = MemAlloc(Size);
if( NULL == *OptInfo ) { Result = ERROR_NOT_ENOUGH_MEMORY ; break; }
Ptr += ROUND_UP_COUNT(sizeof(DHCP_OPTION), ALIGN_WORST);
(*OptInfo)->OptionID = ConvertOptIdToRPCValue(ThisAttrib->Dword1, TRUE);
if( IS_FLAGS1_PRESENT(ThisAttrib) ) (*OptInfo)->OptionType = ThisAttrib->Flags1;
else (*OptInfo)->OptionType = 0;
Size2 = Size - ROUND_UP_COUNT(sizeof(DHCP_OPTION), ALIGN_WORST);
Result = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &((*OptInfo)->DefaultValue),
/* OptBuf */ Ptr,
/* Size */ &Size2
);
Ptr += Size2;
(*OptInfo)->OptionName = (LPVOID)Ptr; wcscpy((LPWSTR)Ptr, ThisAttrib->String1);
if( !IS_STRING2_PRESENT(ThisAttrib) ) (*OptInfo)->OptionComment = NULL;
else {
Ptr += sizeof(WCHAR)*(1+ wcslen(ThisAttrib->String1));
(*OptInfo)->OptionComment = (LPVOID)Ptr;
wcscpy((LPWSTR)Ptr, ThisAttrib->String2);
}
Result = ERROR_SUCCESS;
} while(0);
(void) MemArrayFree(&OptDefAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsSetOptionValue sets the required option value in the DS.
//DOC Note that if the option existed earlier, it is overwritten. Also, the
//DOC option definition is not checked against -- so there need not be an
//DOC option type specified.
//DOC Also, this function works assuming that the option has to be written
//DOC to the current object in DS as given by hObject ptr.
//DOC There are requirements on the fmt used in the DS.
DWORD
DhcpDsSetOptionValue( // set option value
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hObject, // handle to object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class for this opt
IN LPWSTR UserClass, // name of user class for this opt
IN DWORD OptId, // option id
IN LPDHCP_OPTION_DATA OptData // what is the option
) //EndExport(function)
{
DWORD Result, Result2, unused, ValueSize;
ARRAY OptAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
LPBYTE Value;
MemArrayInit(&OptAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* Classes */ NULL
);
// if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for option w/ <OptId>
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( NULL == UserClass && IS_STRING4_PRESENT(ThisAttrib) ) {
continue; // user class mismatch
}
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
if( UserClass ) { // need to 've matchin user class
if( !IS_STRING4_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(UserClass, ThisAttrib->String4) ) continue;
}
Result = MemArrayDelElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result
MemFreeFunc(ThisAttrib);
break;
}
}
NothingPresent(&DummyAttrib); // prepare an elt to add to list
// STRING1_PRESENT(&DummyAttrib); // No name or comment
// if( Comment ) STRING2_PRESENT(&DummyAttrib);
if( ClassName ) STRING3_PRESENT(&DummyAttrib);// class name?
if( UserClass ) STRING4_PRESENT(&DummyAttrib);// user class?
DWORD1_PRESENT(&DummyAttrib); // this is option id
BINARY1_PRESENT(&DummyAttrib); // value is this
// FLAGS1_PRESENT(&DummyAttrib); // flags are not currently used
Value = NULL;
ValueSize = 0; // dont know the size, find out
Result = DhcpConvertOptionRPCToRegFormat( // first convert to Reg fmt
OptData,
NULL,
&ValueSize
);
if( ERROR_MORE_DATA != Result ) { // oops unexpected turn of evts
Result = ERROR_DDS_UNEXPECTED_ERROR;
goto Cleanup;
}
Value = MemAlloc(ValueSize); // got the size, allocate the mem
if( NULL == Value ) { // this shouldnt happen actually
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Result = DhcpConvertOptionRPCToRegFormat( // now convert to Reg fmt
OptData,
Value,
&ValueSize
);
if( ERROR_SUCCESS != Result ) { // this should not happen either
return ERROR_DDS_UNEXPECTED_ERROR;
}
DummyAttrib.Dword1 = OptId; // option Id
DummyAttrib.String3 = ClassName; // class Name
DummyAttrib.String4 = UserClass; // user class
DummyAttrib.Binary1 = Value;
DummyAttrib.BinLen1 = ValueSize;
Result = MemArrayAddElement(&OptAttribs, &DummyAttrib);
if( ERROR_SUCCESS != Result ) goto Cleanup; // Add dummy element to list
Result = DhcpDsSetLists( // set the new list in DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* ClassDescriptio.. */ NULL,
/* Classes */ NULL
);
(void)MemArrayLastLoc(&OptAttribs, &Loc); // clear up list to way it was
//- ERROR_SUCCESS == Result
(void)MemArrayDelElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && ThisAttrib == &DummyAttrib
Cleanup: // free up any memory used
(void)MemArrayFree(&OptAttribs, MemFreeFunc);
if( Value ) MemFree(Value);
return Result;
}
//BeginExport(function)
//DOC DhcpDsRemoveOptionValue deletes the required option value from DS
//DOC the specific option value should exist in DS, else error.
//DOC Also, this function works assuming that the option has been written
//DOC to the current object in DS as given by hObject ptr.
//DOC There are requirements on the fmt used in the DS.
DWORD
DhcpDsRemoveOptionValue( // remove option value
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hObject, // handle to object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class for this opt
IN LPWSTR UserClass, // user class for opt
IN DWORD OptId // option id
) //EndExport(function)
{
DWORD Result, Result2, unused, ValueSize;
ARRAY OptAttribs;
PEATTRIB ThisAttrib;
ARRAY_LOCATION Loc;
MemArrayInit(&OptAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* Classes */ NULL
);
// if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for option w/ <OptId>
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( NULL == UserClass && IS_STRING4_PRESENT(ThisAttrib) ) {
continue; // user class mismatch
}
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
if( UserClass ) { // need to 've matchin user class
if( !IS_STRING4_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(UserClass, ThisAttrib->String4) ) continue;
}
Result = ERROR_SUCCESS;
break;
}
}
if( ERROR_SUCCESS != Result ) { // option was not present in DS
return ERROR_DDS_OPTION_DOES_NOT_EXIST;
}
Result = MemArrayDelElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result
MemFreeFunc(ThisAttrib);
Result = DhcpDsSetLists( // set the new list in DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* ClassDescriptio.. */ NULL,
/* Classes */ NULL
);
(void)MemArrayFree(&OptAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsGetOptionValue retrieves the particular option value in question.
//DOC This function returns ERROR_DDS_OPTION_DOES_NOT_EXIST if the option was
//DOC not found.
DWORD
DhcpDsGetOptionValue( // get option value frm DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hObject, // handle to object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class for this opt
IN LPWSTR UserClass, // user class this opt belongs 2
IN DWORD OptId, // option id
OUT LPDHCP_OPTION_VALUE *OptionValue // allocate and fill this ptr
) //EndExport(function)
{
DWORD Result, Result2, unused, Size, Size2;
ARRAY OptAttribs;
PEATTRIB ThisAttrib;
ARRAY_LOCATION Loc;
LPDHCP_OPTION_VALUE LocalOptionValue;
*OptionValue = NULL;
LocalOptionValue = NULL;
MemArrayInit(&OptAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* Classes */ NULL
);
// if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for option w/ <OptId>
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( NULL == UserClass && IS_STRING4_PRESENT(ThisAttrib) ) {
continue; // user class mismatch
}
if( IS_DWORD1_PRESENT(ThisAttrib) && OptId == ThisAttrib->Dword1 ) {
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
if( UserClass ) { // need to 've matchin user class
if( !IS_STRING4_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(UserClass, ThisAttrib->String4) ) continue;
}
Result = ERROR_SUCCESS;
break;
}
Result = ERROR_SUCCESS; // perfect match
break;
}
if( ERROR_SUCCESS != Result ) { // option was not present in DS
return ERROR_DDS_OPTION_DOES_NOT_EXIST;
}
Size2 = 0; // calculate the size reqd for mem
Size = ROUND_UP_COUNT(sizeof(*LocalOptionValue), ALIGN_WORST);
Result = DhcpConvertOptionRegToRPCFormat2( // convert from RPC to registry fmt
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL,
/* OptBuf */ NULL,
/* Size */ &Size2 // just calculate the size..
);
if( ERROR_MORE_DATA != Result ) { // cant really go wrong
Result = ERROR_DDS_UNEXPECTED_ERROR;
goto Cleanup;
}
LocalOptionValue = MemAlloc(Size);
if( NULL == LocalOptionValue ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
LocalOptionValue->OptionID = ConvertOptIdToRPCValue(OptId, TRUE);
Size2 = Size - ROUND_UP_COUNT(sizeof(*LocalOptionValue), ALIGN_WORST);
Result = DhcpConvertOptionRegToRPCFormat2( // convert from RPC to registry fmt
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &LocalOptionValue->Value,
/* OptBuf */ ROUND_UP_COUNT(sizeof(*LocalOptionValue), ALIGN_WORST) + (LPBYTE)LocalOptionValue,
/* Size */ &Size2 // just calculate the size..
);
if( ERROR_SUCCESS != Result ) { // cant really go wrong
if( ERROR_MORE_DATA == Result ) { // this can cause confusion..
Result = ERROR_DDS_UNEXPECTED_ERROR;
}
goto Cleanup;
}
*OptionValue = LocalOptionValue;
Cleanup:
if( ERROR_SUCCESS != Result ) {
if( LocalOptionValue ) MemFreeFunc(LocalOptionValue);
*OptionValue = NULL;
}
(void)MemArrayFree(&OptAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsEnumOptionValues enumerates the list of options for a given class
//DOC Also, depending on whether IsVendor is TRUE or false, this function enumerates
//DOC only vendor specific or only non-vendor-specific options respectively.
//DOC This function gets the whole bunch in one shot.
DWORD
DhcpDsEnumOptionValues( // get option values from DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hObject, // handle to object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class for this opt
IN LPWSTR UserClass, // for which user class?
IN DWORD IsVendor, // enum only vendor/non-vendor?
OUT LPDHCP_OPTION_VALUE_ARRAY *OptionValues // allocate option values..
) //EndExport(function)
{
DWORD Result, Result2, unused, Size, Size2, i;
DWORD AllocSize;
ARRAY OptAttribs;
PEATTRIB ThisAttrib;
ARRAY_LOCATION Loc;
LPDHCP_OPTION_VALUE_ARRAY LocalOptionValueArray;
LPBYTE Ptr;
*OptionValues = NULL;
LocalOptionValueArray = NULL;
MemArrayInit(&OptAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* Classes */ NULL
);
// if( ERROR_SUCCESS != Result ) return Result;
Size = i = 0;
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // go thru each option, calc size
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_DWORD1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // illegal attrib, or not this opt
}
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( NULL == UserClass && IS_STRING4_PRESENT(ThisAttrib) ) {
continue; // user class mismatch
}
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
if( UserClass ) { // need to 've matchin user class
if( !IS_STRING4_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(UserClass, ThisAttrib->String4) ) continue;
}
Size2 = 0; // calculate the size reqd for mem
Result2= DhcpConvertOptionRegToRPCFormat2(// convert from RPC to registry fmt
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL,
/* OptBuf */ NULL,
/* Size */ &Size2 // just calculate the size..
);
if( ERROR_MORE_DATA != Result2 ) { // cant really go wrong
continue; // skip this attrib in this case
}
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
i ++;
}
Size += ROUND_UP_COUNT( i * sizeof(DHCP_OPTION_VALUE), ALIGN_WORST);
Size += ROUND_UP_COUNT( sizeof(DHCP_OPTION_VALUE_ARRAY ), ALIGN_WORST);
Ptr = MemAlloc(AllocSize = Size); LocalOptionValueArray = (LPVOID)Ptr;
if( NULL == LocalOptionValueArray ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Ptr += ROUND_UP_COUNT( sizeof(DHCP_OPTION_VALUE_ARRAY ), ALIGN_WORST);
LocalOptionValueArray->Values = (LPVOID)Ptr;
Ptr += ROUND_UP_COUNT( i * sizeof(DHCP_OPTION_VALUE), ALIGN_WORST);
Size = i = 0;
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // go thru each opt, fill data
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_DWORD1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // illegal attrib, or not this opt
}
if( NULL == ClassName && IS_STRING3_PRESENT(ThisAttrib) ) {
continue; // classname mismatch
}
if( NULL == UserClass && IS_STRING4_PRESENT(ThisAttrib) ) {
continue; // user class mismatch
}
if( ClassName ) { // need to have matching class
if( !IS_STRING3_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(ClassName, ThisAttrib->String3) ) continue;
}
if( UserClass ) { // need to 've matchin user class
if( !IS_STRING4_PRESENT(ThisAttrib) ) continue;
if( 0 != wcscmp(UserClass, ThisAttrib->String4) ) continue;
}
Size2 = AllocSize - Size;
Result2= DhcpConvertOptionRegToRPCFormat2(// convert from RPC to registry fmt
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &LocalOptionValueArray->Values[i].Value,
/* OptBuf */ Ptr,
/* Size */ &Size2 // just calculate the size..
);
if( ERROR_SUCCESS != Result2 ) { // cant really go wrong
continue; // skip this attrib in this case
}
LocalOptionValueArray->Values[i].OptionID = ConvertOptIdToRPCValue(ThisAttrib->Dword1, TRUE);
Size += ROUND_UP_COUNT(Size2, ALIGN_WORST);
Ptr += ROUND_UP_COUNT(Size2, ALIGN_WORST);
i ++;
}
LocalOptionValueArray->NumElements = i;
*OptionValues = LocalOptionValueArray;
Cleanup:
if( ERROR_SUCCESS != Result ) {
if( LocalOptionValueArray ) MemFreeFunc(LocalOptionValueArray);
*OptionValues = NULL;
}
(void)MemArrayFree(&OptAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsCreateClass creates a given class in the DS. The class should not
//DOC exist prior to this in the DS (if it does, this fn returns error
//DOC ERROR_DDS_CLASS_EXISTS).
DWORD
DhcpDsCreateClass( // create this class in the ds
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class..
IN LPWSTR ClassComment, // comment for this class
IN LPBYTE ClassData, // the bytes that form the class data
IN DWORD ClassDataLen, // # of bytes of above
IN BOOL IsVendor // is this a vendor class?
) //EndExport(function)
{
DWORD Result, Result2, unused;
ARRAY ClassAttribs;
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
if( NULL == ClassName || NULL == ClassData || 0 == ClassDataLen )
return ERROR_INVALID_PARAMETER;
MemArrayInit(&ClassAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ &ClassAttribs
);
// if( ERROR_SUCCESS != Result ) return Result;
Result = MemArrayInitLoc(&ClassAttribs, &Loc);
while( ERROR_FILE_NOT_FOUND != Result ) { // search for existing class
Result = MemArrayGetElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
Result = MemArrayNextLoc(&ClassAttribs, &Loc);
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // invalid attrib for a class
}
if( 0 == wcscmp(ClassName, ThisAttrib->String1) ) {
Result = ERROR_DDS_CLASS_EXISTS; // gotcha! same name
goto Cleanup;
}
}
NothingPresent(&DummyAttrib); // create an attrib for the class
STRING1_PRESENT(&DummyAttrib); // class name
if( ClassComment ) {
STRING2_PRESENT(&DummyAttrib); // class comment
}
BINARY1_PRESENT(&DummyAttrib); // class data
FLAGS1_PRESENT(&DummyAttrib); // vendorclass etc information
DummyAttrib.String1 = ClassName; // now fill in the actual values
DummyAttrib.String2 = ClassComment;
DummyAttrib.Binary1 = ClassData;
DummyAttrib.BinLen1 = ClassDataLen;
DummyAttrib.Flags1 = IsVendor;
Result = MemArrayAddElement(&ClassAttribs, &DummyAttrib);
if( ERROR_SUCCESS != Result ) { // could not add an elt? uh uh.
goto Cleanup;
}
Result = DhcpDsSetLists( // write back the modified list
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* ClassDescriptio.. */ NULL,
/* Classes */ &ClassAttribs
);
// now try to remove the dummy element that was added..
Result2 = MemArrayLastLoc(&ClassAttribs, &Loc);
//- ERROR_SUCCESS == Result2
Result2 = MemArrayDelElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result2 && ThisAttrib == &DummyAttrib
Cleanup:
(void) MemArrayFree(&ClassAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsDeleteClass deletes the class from off the DS, and returns an error
//DOC if the class did not exist in the DS for hte given server object.
DWORD
DhcpDsDeleteClass( // delete the class from the ds
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName // name of class..
) //EndExport(function)
{
DWORD Result, Result2, unused;
ARRAY ClassAttribs;
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
if( NULL == ClassName ) return ERROR_INVALID_PARAMETER;
MemArrayInit(&ClassAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ &ClassAttribs
);
// if( ERROR_SUCCESS != Result ) return Result;
for( Result = MemArrayInitLoc(&ClassAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for existing class
Result = MemArrayNextLoc(&ClassAttribs, &Loc)
) {
Result = MemArrayGetElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // invalid attrib for a class
}
if( 0 == wcscmp(ClassName, ThisAttrib->String1) ) {
Result = ERROR_SUCCESS; // gotcha! same name
break;
}
}
if( ERROR_SUCCESS != Result ) {
Result = ERROR_DDS_CLASS_DOES_NOT_EXIST;
goto Cleanup;
}
Result = MemArrayDelElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
MemFreeFunc(ThisAttrib);
Result = DhcpDsSetLists( // write back the modified list
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* SetParams */ &unused,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescripti.. */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* ClassDescriptio.. */ NULL,
/* Classes */ &ClassAttribs
);
Cleanup:
(void) MemArrayFree(&ClassAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC this is not yet implemented.
DWORD
DhcpDsModifyClass( // modify a class in the DS
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // name of class -- this is the key
IN LPWSTR ClassComment, // comment for this class
IN LPBYTE ClassData, // the bytes that form the class data
IN DWORD ClassDataLen // # of bytes of above
) //EndExport(function)
{
return ERROR_CALL_NOT_IMPLEMENTED;
}
//BeginExport(function)
//DOC DhcpDsGetClassInfo get information on a class by doing a search based
//DOC on either the class name or the class data fields. ClassName is guaranteed
//DOC to be unique. ClassData may/maynot be unique. The search is done in the DS,
//DOC so things are likely to be a lot slower than they should be.
//DOC This should be fixed by doing some intelligent searches.
//DOC Note that the hServer and the hDhcpC handles should point to the right objects.
//DOC
DWORD
DhcpDsGetClassInfo( // get class details for given class
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
IN LPWSTR ClassName, // OPTIONAL search on class name
IN LPBYTE ClassData, // OPTIONAL srch on class data
IN DWORD ClassDataLen, // # of bytes of ClassData
OUT LPDHCP_CLASS_INFO *ClassInfo // allocate and copy ptr
) //EndExport(function)
{
DWORD Result, Result2, Size;
DWORD IsVendor, Flags;
ARRAY ClassAttribs;
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
LPDHCP_CLASS_INFO LocalClassInfo;
LPBYTE Ptr;
LPWSTR ClassComment;
if( NULL == ClassName || NULL == ClassData || 0 == ClassDataLen )
return ERROR_INVALID_PARAMETER;
LocalClassInfo = *ClassInfo = NULL;
MemArrayInit(&ClassAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ &ClassAttribs
);
// if( ERROR_SUCCESS != Result ) return Result;
Result = MemArrayInitLoc(&ClassAttribs, &Loc);
while( ERROR_FILE_NOT_FOUND != Result ) { // search for existing class
Result = MemArrayGetElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
Result = MemArrayNextLoc(&ClassAttribs, &Loc);
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // invalid attrib for a class
}
if( 0 == ThisAttrib->BinLen1 ) { // invalid attrib for this class
continue;
}
if( ClassName ) { // if srching on ClassName field
if( 0 == wcscmp(ClassName, ThisAttrib->String1) ) {
Result = ERROR_SUCCESS; // gotcha! same name
break;
}
} else { // srching on ClassData field
if( ClassDataLen != ThisAttrib->BinLen1 )
continue; // nope mismatch
if( 0 == memcpy(ClassData, ThisAttrib->Binary1, ClassDataLen) ) {
Result = ERROR_SUCCESS; // gotcha! matching bits
break;
}
}
}
if( ERROR_SUCCESS != Result ) { // did not find the class
Result = ERROR_DDS_CLASS_DOES_NOT_EXIST;
goto Cleanup;
}
ClassName = ThisAttrib->String1;
if( IS_STRING2_PRESENT(ThisAttrib) ) {
ClassComment = ThisAttrib->String2;
} else {
ClassComment = NULL;
}
ClassData = ThisAttrib->Binary1;
ClassDataLen = ThisAttrib->BinLen1;
if( IS_FLAGS1_PRESENT(ThisAttrib) ) {
IsVendor = ThisAttrib->Flags1;
} else IsVendor = 0;
if( IS_FLAGS2_PRESENT(ThisAttrib) ) {
Flags = ThisAttrib->Flags2;
} else Flags = 0;
Size = 0; // calculate size reqd
Size = ROUND_UP_COUNT(sizeof(DHCP_CLASS_INFO),ALIGN_WORST);
Size += sizeof(WCHAR)*(wcslen(ClassName)+1); // alloc space for name
if( ClassComment ) { // alloc space for comment
Size += sizeof(WCHAR)*(wcslen(ClassComment) +1);
}
Size += ThisAttrib->BinLen1; // alloc space for data
Ptr = MemAlloc(Size); // allocate memory
LocalClassInfo = (LPVOID)Ptr;
if( NULL == LocalClassInfo ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Size = 0; // copy the stuff in
Size = ROUND_UP_COUNT(sizeof(DHCP_CLASS_INFO),ALIGN_WORST);
LocalClassInfo->ClassName = (LPVOID)(Size + Ptr);
wcscpy(LocalClassInfo->ClassName, ClassName);
Size += sizeof(WCHAR)*(wcslen(ClassName)+1);
if( NULL == ClassComment ) {
LocalClassInfo->ClassComment = NULL;
} else {
LocalClassInfo->ClassComment = (LPVOID)(Size + Ptr);
wcscpy(LocalClassInfo->ClassComment, ThisAttrib->String2 );
Size += sizeof(WCHAR)*(wcslen(ThisAttrib->String2) +1);
}
LocalClassInfo->ClassDataLength = ThisAttrib->BinLen1;
LocalClassInfo->ClassData = Size+Ptr;
memcpy(LocalClassInfo->ClassData, ThisAttrib->Binary1, ThisAttrib->BinLen1);
LocalClassInfo->IsVendor = IsVendor;
LocalClassInfo->Flags = Flags;
*ClassInfo = LocalClassInfo;
Result = ERROR_SUCCESS;
Cleanup:
(void) MemArrayFree(&ClassAttribs, MemFreeFunc);
return Result;
}
//BeginExport(function)
//DOC DhcpDsEnumClasses enumerates the classes for a given server (as specified
//DOC via the hServer object.)
//DOC The memory for Classes is allocated by this function.
DWORD
DhcpDsEnumClasses( // get the list of classes frm ds
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
IN OUT LPSTORE_HANDLE hServer, // handle to server object in DS
IN DWORD Reserved, // must be zero, future use
OUT LPDHCP_CLASS_INFO_ARRAY *Classes // allocate memory for this
) //EndExport(function)
{
DWORD Result, Result2, Size, Size2, i;
DWORD ClassDataLen, IsVendor, Flags;
ARRAY ClassAttribs;
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
LPDHCP_CLASS_INFO_ARRAY LocalClassInfoArray;
LPBYTE Ptr, ClassData;
LPWSTR ClassName, ClassComment;
LocalClassInfoArray = *Classes = NULL;
MemArrayInit(&ClassAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ &ClassAttribs
);
// if( ERROR_SUCCESS != Result ) return Result;
Result = MemArrayInitLoc(&ClassAttribs, &Loc);
for(Size = i = 0 // search for existing classes
; ERROR_FILE_NOT_FOUND != Result;
Result = MemArrayNextLoc(&ClassAttribs, &Loc)
) {
Result = MemArrayGetElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // invalid attrib for a class
}
if( 0 == ThisAttrib->BinLen1 ) { // invalid attrib for this class
continue;
}
ClassName = ThisAttrib->String1;
if( IS_STRING2_PRESENT(ThisAttrib) ) {
ClassComment = ThisAttrib->String2;
} else {
ClassComment = NULL;
}
ClassData = ThisAttrib->Binary1;
ClassDataLen = ThisAttrib->BinLen1;
Size += sizeof(WCHAR)*(wcslen(ClassName)+1);
if( ClassComment ) { // alloc space for comment
Size += sizeof(WCHAR)*(wcslen(ClassComment) +1);
}
Size += ROUND_UP_COUNT(ClassDataLen,ALIGN_WORST);
i ++;
}
Size += ROUND_UP_COUNT(i*sizeof(DHCP_CLASS_INFO), ALIGN_WORST);
Size += ROUND_UP_COUNT(sizeof(DHCP_CLASS_INFO_ARRAY), ALIGN_WORST);
Ptr = MemAlloc(Size); // allocate memory
LocalClassInfoArray = (LPVOID)Ptr;
if( NULL == LocalClassInfoArray ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Size = 0; // copy the stuff in
LocalClassInfoArray->NumElements = i;
Size += ROUND_UP_COUNT(sizeof(DHCP_CLASS_INFO_ARRAY), ALIGN_WORST);
LocalClassInfoArray->Classes = (LPVOID) (Size + Ptr);
Size += ROUND_UP_COUNT(i*sizeof(DHCP_CLASS_INFO), ALIGN_WORST);
Result = MemArrayInitLoc(&ClassAttribs, &Loc);
for(i = 0 // fill in the array with details
; ERROR_FILE_NOT_FOUND != Result;
Result = MemArrayNextLoc(&ClassAttribs, &Loc)
) {
Result = MemArrayGetElement(&ClassAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // invalid attrib for a class
}
if( 0 == ThisAttrib->BinLen1 ) { // invalid attrib for this class
continue;
}
ClassName = ThisAttrib->String1;
if( IS_STRING2_PRESENT(ThisAttrib) ) {
ClassComment = ThisAttrib->String2;
} else {
ClassComment = NULL;
}
ClassData = ThisAttrib->Binary1;
ClassDataLen = ThisAttrib->BinLen1;
LocalClassInfoArray->Classes[i].ClassName = (LPVOID)(Size + Ptr);
wcscpy(LocalClassInfoArray->Classes[i].ClassName, ClassName);
Size += sizeof(WCHAR)*(wcslen(ClassName)+1);
if( NULL == ClassComment ) {
LocalClassInfoArray->Classes[i].ClassComment = NULL;
} else {
LocalClassInfoArray->Classes[i].ClassComment = (LPVOID)(Size + Ptr);
wcscpy(LocalClassInfoArray->Classes[i].ClassComment, ThisAttrib->String2 );
Size += sizeof(WCHAR)*(wcslen(ClassComment) +1);
}
LocalClassInfoArray->Classes[i].ClassDataLength = ClassDataLen;
LocalClassInfoArray->Classes[i].ClassData = Size+Ptr;
memcpy(LocalClassInfoArray->Classes[i].ClassData, ClassData,ClassDataLen);
Size += ROUND_UP_COUNT(ClassDataLen,ALIGN_WORST);
if( IS_FLAGS1_PRESENT(ThisAttrib) ) {
IsVendor = ThisAttrib->Flags1;
} else IsVendor = 0;
if( IS_FLAGS2_PRESENT(ThisAttrib) ) {
Flags = ThisAttrib->Flags2;
} else Flags = 0;
LocalClassInfoArray->Classes[i].IsVendor = IsVendor;
LocalClassInfoArray->Classes[i].Flags = Flags;
i ++;
}
*Classes = LocalClassInfoArray;
Result = ERROR_SUCCESS;
Cleanup:
(void) MemArrayFree(&ClassAttribs, MemFreeFunc);
return Result;
}
//================================================================================
// get all optinos and get all option values code
//================================================================================
BOOL
TripletNewlyAdded( // check to see if triplet is old or new
IN PARRAY UClasses, // array of strings
IN PARRAY VClasses, // array of strings again
IN PARRAY IsVendorVals, // this is an array of booleans..
IN LPWSTR UClass, // user class
IN LPWSTR VClass, // venodr class
IN ULONG IsVendor // is this vendor or not?
)
{
ARRAY_LOCATION Loc1, Loc2, Loc3;
DWORD Result, Size, ThisIsVendor;
LPWSTR ThisUClass, ThisVClass;
Result = MemArrayInitLoc(UClasses, &Loc1);
Result = MemArrayInitLoc(VClasses, &Loc2);
Result = MemArrayInitLoc(IsVendorVals, &Loc3);
for(
; ERROR_FILE_NOT_FOUND != Result ;
Result = MemArrayNextLoc(UClasses, &Loc1),
Result = MemArrayNextLoc(VClasses, &Loc2),
Result = MemArrayNextLoc(IsVendorVals, &Loc3)
) {
MemArrayGetElement(UClasses, &Loc1, &ThisUClass);
MemArrayGetElement(VClasses, &Loc2, &ThisVClass);
MemArrayGetElement(IsVendorVals, &Loc3, (LPVOID *)&ThisIsVendor);
if( ThisIsVendor != IsVendor ) continue;
if( NULL == ThisUClass && NULL != UClass ||
NULL == UClass && NULL != ThisUClass ) continue;
if( NULL != ThisUClass && 0 != wcscmp(ThisUClass, UClass) ) continue;
if( NULL == ThisVClass && NULL != VClass ||
NULL == VClass && NULL != ThisVClass ) continue;
if( NULL != ThisVClass && 0 != wcscmp(ThisVClass, VClass) ) continue;
return FALSE; // triplet already found!
}
// New triplet try to add..
Result = MemArrayAddElement(IsVendorVals, ULongToPtr(IsVendor));
if( ERROR_SUCCESS != Result ) return FALSE;
Result = MemArrayAddElement(VClasses, VClass);
if( ERROR_SUCCESS != Result ) return FALSE;
Result = MemArrayAddElement(UClasses, UClass);
if ( ERROR_SUCCESS != Result ) return FALSE;
return TRUE;
}
DWORD
ClassifyAndAddOptionValues( // find if this combo is alreayd there?
IN PEATTRIB ThisAttrib, // attribute to process
IN PARRAY UClasses, // array of user class strings +
IN PARRAY VClasses, // array of vernor class strings +
IN PARRAY IsVendorVals, // array of isvendor values
IN OUT PULONG StringSpace, // amout of space reqd to store strings
IN OUT PULONG BinSpace, // amount of space required to store bins..
IN OUT PULONG OptionCount // # of option values in all.
)
{
ULONG Err, Size;
LPWSTR UClass, VClass;
ULONG IsVendor;
UClass = IS_STRING4_PRESENT(ThisAttrib)? ThisAttrib->String4 : NULL;
VClass = IS_STRING3_PRESENT(ThisAttrib)? ThisAttrib->String3 : NULL;
IsVendor = CheckForVendor(ThisAttrib->Dword1, TRUE);
if( TripletNewlyAdded(UClasses, VClasses, IsVendorVals, UClass, VClass, IsVendor) ) {
// this triplet was not present before but was just added... need to make space..
if( UClass ) (*StringSpace) += 1 + wcslen(UClass);
if( VClass ) (*StringSpace) += 1 + wcslen(VClass);
}
Size = 0;
Err = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL,
/* OptBuf */ NULL,
/* Size */ &Size // just calculate the size..
);
if( ERROR_MORE_DATA != Err && ERROR_SUCCESS != Err ) {
return Err; // oops strange error..
}
(*BinSpace) += Size; // ok additional binary space is this..
(*OptionCount) ++; // one more option..
return ERROR_SUCCESS;
}
DWORD
CalculateOptionValuesSize( // amount of space required for storing...
IN ULONG nElements, // # of triples of <classid/vendorid/isvendor>
IN ULONG StringSpace, // # of WCHARs of strings requried
IN ULONG BinSpace, // # of bytes of space requried for storage of bin..
IN ULONG OptCount // total # of options values
)
{
ULONG Size; // return value.
DHCP_ALL_OPTION_VALUES AllValues;
// basic strucutre
Size = ROUND_UP_COUNT(sizeof(AllValues), ALIGN_WORST);
// array of triplets
Size += nElements * ( sizeof(*(AllValues.Options)) );
Size = ROUND_UP_COUNT( Size, ALIGN_WORST);
// each triplet also has an array in it.. the basic struc..
Size += nElements * ( sizeof(*(AllValues.Options->OptionsArray)) );
Size = ROUND_UP_COUNT( Size, ALIGN_WORST);
// now comes the arrays of options actually
Size += OptCount * sizeof(DHCP_OPTION_VALUE);
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
// now the space to store the strings..
Size += sizeof(WCHAR)*StringSpace;
// now to store the binaries..
Size += BinSpace;
return Size;
}
DWORD
AddSpecificOptionValues( // for this triple, add all options to array
IN OUT LPDHCP_OPTION_VALUE_ARRAY Values, // array to fill
IN LPWSTR UClass, // the user class of this set of values
IN LPWSTR VClass, // the vendor class of this set of values
IN ULONG IsVendor, // is it vendor or not?
IN PARRAY InputValues, // array of PEATTRIB types from DS
IN OUT LPDHCP_OPTION_VALUE *OptionValues, // use this for space and update it..
IN OUT LPBYTE *Ptr // use this for binary space and update it..
)
{
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
DWORD Result, Size, ThisIsVendor;
LPWSTR ThisUClass, ThisVClass;
Values->NumElements = 0;
Values->Values = (*OptionValues);
for( Result = MemArrayInitLoc(InputValues, &Loc)
; ERROR_FILE_NOT_FOUND != Result ;
Result = MemArrayNextLoc(InputValues, &Loc)
) {
MemArrayGetElement(InputValues, &Loc, &ThisAttrib);
ThisUClass = IS_STRING4_PRESENT(ThisAttrib)? ThisAttrib->String4 : NULL;
ThisVClass = IS_STRING3_PRESENT(ThisAttrib)? ThisAttrib->String3 : NULL;
ThisIsVendor = CheckForVendor(ThisAttrib->Dword1, TRUE);
if( ThisIsVendor != IsVendor ) continue;
if( NULL == ThisUClass && NULL != UClass ||
NULL == UClass && NULL != ThisUClass ) continue;
if( NULL != ThisUClass && 0 != wcscmp(ThisUClass, UClass) ) continue;
if( NULL == ThisVClass && NULL != VClass ||
NULL == VClass && NULL != ThisVClass ) continue;
if( NULL != ThisVClass && 0 != wcscmp(ThisVClass, VClass) ) continue;
// matched.. increase count.. convert option.. move pointers..
Values->NumElements ++;
(*OptionValues)->OptionID = ThisAttrib->Dword1;
Size = 0xFFFFFFFF; // dont know size but definitely enough
Result = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &(*OptionValues)->Value,
/* OptBuf */ (*Ptr),
/* Size */ &Size // just calculate the size..
);
if( ERROR_MORE_DATA != Result && ERROR_SUCCESS != Result ) {
return Result; // oops strange error..
}
(*OptionValues) ++;
(*Ptr) += Size;
}
return ERROR_SUCCESS;
}
DWORD
FillOptionValues( // fill optiosn according to pattern laid out above..
IN PARRAY Options, // teh options to fill
IN PARRAY UClasses, // the user classes
IN PARRAY VClasses, // the vendor classes
IN PARRAY IsVendorVals, // Isvenodr values
IN ULONG StringSpace, // how much space for strings?
IN ULONG BinSpace, // how much space for bins?
IN ULONG OptCount, // total # of options
OUT LPDHCP_ALL_OPTION_VALUES Values // fill this out and returns
)
{
DHCP_ALL_OPTION_VALUES AllValues;
ULONG Result, nElements, Size;
LPBYTE Ptr = (LPBYTE)Values;
LPWSTR Strings;
LPDHCP_OPTION_VALUE OptionValuesArray;
int i;
ARRAY_LOCATION Loc1, Loc2, Loc3;
LPVOID ThisElt;
// basic strucutre
Size = ROUND_UP_COUNT(sizeof(AllValues), ALIGN_WORST);
Ptr = Size + (LPBYTE)Values;
Values->NumElements = nElements = MemArraySize(UClasses);
Values->Flags = 0;
Values->Options = (LPVOID)Ptr;
// array of triplets
Size += nElements * ( sizeof(*(AllValues.Options)) );
Size = ROUND_UP_COUNT( Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)Values;
// each triplet also has an array in it.. the basic struc..
for( i = 0; i < (int)nElements; i ++ ) {
Values->Options[i].OptionsArray = (LPVOID)Ptr;
Ptr += sizeof(*(AllValues.Options->OptionsArray));
}
Size += nElements * ( sizeof(*(AllValues.Options->OptionsArray)) );
Size = ROUND_UP_COUNT( Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)Values;
// now comes the arrays of options actually
OptionValuesArray = (LPVOID) Ptr;
Size += OptCount * sizeof(DHCP_OPTION_VALUE);
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)Values;
// now the space to store the strings..
Strings = (LPWSTR)Ptr;
Size += sizeof(WCHAR)*StringSpace;
// now to store the binaries..
Ptr = Size + (LPBYTE)Values;
Size += BinSpace;
// now do the filling in earnestly.
MemArrayInitLoc(UClasses, &Loc1);
MemArrayInitLoc(VClasses, &Loc2);
MemArrayInitLoc(IsVendorVals, &Loc3);
for( i = 0; i < (int)nElements ; i ++ ) {
LPWSTR UClass, VClass;
ULONG IsVendor;
MemArrayGetElement(UClasses, &Loc1, &UClass);
MemArrayGetElement(VClasses, &Loc2, &VClass);
MemArrayGetElement(IsVendorVals, &Loc3, (LPVOID *)&IsVendor);
MemArrayNextLoc(UClasses, &Loc1);
MemArrayNextLoc(VClasses, &Loc2);
MemArrayNextLoc(IsVendorVals, &Loc3);
if( NULL == UClass ) {
Values->Options[i].ClassName = NULL;
} else {
Values->Options[i].ClassName = Strings;
wcscpy(Strings, UClass);
Strings += 1 + wcslen(UClass);
}
if( NULL == VClass ) {
Values->Options[i].VendorName = NULL;
} else {
Values->Options[i].VendorName = Strings;
wcscpy(Strings, VClass);
Strings += 1 + wcslen(VClass);
}
Values->Options[i].IsVendor = IsVendor;
Result = AddSpecificOptionValues(
Values->Options[i].OptionsArray,
UClass, VClass, IsVendor,
Options,
&OptionValuesArray,
&Ptr
);
if( ERROR_SUCCESS != Result ) return Result;
}
return ERROR_SUCCESS;
}
//BeginExport(function)
//DOC This function retrieves all the option valuesdefined for this object frm th dS
DWORD
DhcpDsGetAllOptionValues(
IN LPSTORE_HANDLE hDhcpC,
IN LPSTORE_HANDLE hObject,
IN DWORD Reserved,
OUT LPDHCP_ALL_OPTION_VALUES *OptionValues
) //EndExport(function)
{
DWORD Result, Result2, unused, Size, Size2, i;
DWORD AllocSize;
ARRAY OptAttribs;
PEATTRIB ThisAttrib;
ARRAY_LOCATION Loc;
LPDHCP_OPTION_VALUE_ARRAY LocalOptionValueArray;
LPBYTE Ptr;
ARRAY UserClassNames;
ARRAY VendorClassNames;
ARRAY IsVendorValues;
ULONG StringSpace, BinSpace;
ULONG OptionCount, ElementCount;
*OptionValues = NULL;
LocalOptionValueArray = NULL;
MemArrayInit(&OptAttribs);
Result = DhcpDsGetLists( // get list of options frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hObject,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ NULL,
/* OptionsLocation */ NULL,
/* Options */ &OptAttribs,
/* Classes */ NULL
);
// if( ERROR_SUCCESS != Result ) return Result;
StringSpace = 0; BinSpace = 0; OptionCount = 0;
MemArrayInit(&UserClassNames);
MemArrayInit(&VendorClassNames);
MemArrayInit(&IsVendorValues);
for( Result = MemArrayInitLoc(&OptAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // go thru each option, calc size
Result = MemArrayNextLoc(&OptAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_DWORD1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib) ) {
continue; // illegal attrib, or not this opt
}
Result = ClassifyAndAddOptionValues(
ThisAttrib, &UserClassNames, &VendorClassNames, &IsVendorValues,
&StringSpace, &BinSpace, &OptionCount
);
if( ERROR_SUCCESS != Result ) goto Cleanup;
}
// total space required calculation...
ElementCount = MemArraySize(&UserClassNames); // same as vendor class etc..
Size = CalculateOptionValuesSize(ElementCount, StringSpace, BinSpace, OptionCount);
(*OptionValues) = MemAlloc(Size);
if( NULL == (*OptionValues) ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Result = FillOptionValues(
&OptAttribs, &UserClassNames, &VendorClassNames, &IsVendorValues,
StringSpace, BinSpace, OptionCount,
(*OptionValues)
);
if( ERROR_SUCCESS != Result ) {
MemFree(*OptionValues);
*OptionValues = NULL;
}
Cleanup:
MemArrayFree(&OptAttribs, MemFreeFunc);
MemArrayFree(&UserClassNames, MemFreeFunc);
MemArrayFree(&VendorClassNames, MemFreeFunc);
MemArrayFree(&IsVendorValues, MemFreeFunc);
return Result;
}
DWORD
ClassifyAndAddOption( // classify as vendor/non-vendor etc
IN PEATTRIB ThisAttrib, // attrib to classify
IN PULONG StringSpace, // add to this the space reqd for strings
IN PULONG BinSpace, // add to this the space reqd for bin.
IN PULONG VendorCount, // increment if vendor
IN PULONG NonVendorCount // increment if non-vendor
)
{
BOOL IsVendor;
ULONG Result, Size;
if( CheckForVendor(ThisAttrib->Dword1, TRUE) ) {
(*VendorCount) ++; // vendor specific option..
IsVendor = TRUE;
if( IS_STRING3_PRESENT(ThisAttrib) ) { // got a class name
(*StringSpace) += 1+wcslen(ThisAttrib->String3);
}
} else {
(*NonVendorCount) ++; // not a vendor option
IsVendor = FALSE;
}
(*StringSpace) += 1+wcslen(ThisAttrib->String1);
if( IS_STRING2_PRESENT(ThisAttrib) ) { // string1 is name, string2 is comment
(*StringSpace) += 1+wcslen(ThisAttrib->String2);
}
Size = 0;
Result = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ NULL,
/* OptBuf */ NULL,
/* Size */ &Size
);
if( ERROR_MORE_DATA != Result && ERROR_SUCCESS != Result ) {
return Result;
}
(*BinSpace) += Size;
return ERROR_SUCCESS;
}
DWORD
CalculateOptionsSize( // calc amt storage reqd for this..
IN ULONG VendorCount, // # of vendor options
IN ULONG NonVendorCount,// # of non-vendor options
IN ULONG StringSpace, // # of WCHAR string chars
IN ULONG BinSpace // # of bytes for binary data..
)
{
ULONG Size;
LPDHCP_ALL_OPTIONS AllOptions; // dummy structure..
// First comes the structure itself
Size = ROUND_UP_COUNT(sizeof(*AllOptions), ALIGN_WORST);
// Next comes the space for a NonVendorOptions array
Size += sizeof(*(AllOptions->NonVendorOptions));
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
// Next comes the non-vendor optiosn themselves
Size += NonVendorCount * sizeof(DHCP_OPTION);
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
// Next comes the vendor options structure..
Size += VendorCount * sizeof(*(AllOptions->VendorOptions));
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
// Next store the strings..
Size += sizeof(WCHAR)*StringSpace;
// Next store the binary information..
Size += BinSpace;
return Size;
}
DWORD
AddSpecificOptions( // fill in the structure of optiosn..
IN OUT LPDHCP_ALL_OPTIONS AllOptions, // this is the structure to fill in
IN LPWSTR Strings, // Buffer to use to fill in all strings
IN LPBYTE BinarySpace, // this is the space to use for bin..
IN PARRAY OptDefs // the array to pick off hte options from
)
{
ULONG Err, Size;
ARRAY_LOCATION Loc;
PEATTRIB ThisAttrib;
ULONG nVendorOpts, nNonVendorOpts;
BOOL IsVendor;
ULONG OptId, OptType;
LPWSTR OptionName;
LPWSTR OptionComment;
LPWSTR VendorName;
LPDHCP_OPTION ThisOption;
AllOptions->Flags = 0;
nVendorOpts = nNonVendorOpts = 0;
for( Err = MemArrayInitLoc(OptDefs, &Loc)
; ERROR_SUCCESS == Err ;
Err = MemArrayNextLoc(OptDefs, &Loc)
) { // process each option
Err = MemArrayGetElement(OptDefs, &Loc, &ThisAttrib);
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib)
|| !IS_DWORD1_PRESENT(ThisAttrib) ) { // invalid attrib
continue; // skip it
}
IsVendor = CheckForVendor(ThisAttrib->Dword1, TRUE );
OptId = ConvertOptIdToRPCValue(ThisAttrib->Dword1, TRUE);
OptType = IS_FLAGS1_PRESENT(ThisAttrib) ? ThisAttrib->Flags1 : 0;
OptionName = ThisAttrib->String1;
OptionComment = IS_STRING2_PRESENT(ThisAttrib) ? ThisAttrib->String2 : NULL;
VendorName = IS_STRING3_PRESENT(ThisAttrib) ? ThisAttrib->String3 : NULL;
if( !IsVendor ) { // fill in the non-vendor part..
ThisOption = &AllOptions->NonVendorOptions->Options[nNonVendorOpts++];
} else {
ThisOption = &AllOptions->VendorOptions[nVendorOpts].Option;
if( !VendorName ) {
AllOptions->VendorOptions[nVendorOpts].VendorName = NULL;
} else {
wcscpy(Strings, VendorName);
AllOptions->VendorOptions[nVendorOpts].VendorName = Strings;
Strings += 1+wcslen(Strings);
}
AllOptions->VendorOptions[nVendorOpts++].ClassName = NULL;
}
Size = 0xFFFFFFFF; // databuffer size is sufficient.. but unkonwn..
Err = DhcpConvertOptionRegToRPCFormat2(
/* Buffer */ ThisAttrib->Binary1,
/* BufferSize */ ThisAttrib->BinLen1,
/* Option */ &ThisOption->DefaultValue,
/* OptBuf */ BinarySpace,
/* Size */ &Size
);
if( ERROR_SUCCESS != Err ) return Err; // barf
BinarySpace += Size; // update sapce ..
ThisOption->OptionID = OptId;
ThisOption->OptionType = OptType;
ThisOption->OptionName = Strings;
wcscpy(Strings, OptionName); Strings += 1+wcslen(Strings);
if( NULL == OptionComment ) {
ThisOption->OptionComment = NULL;
} else {
ThisOption->OptionComment = Strings;
wcscpy(Strings, OptionComment);
Strings += 1 + wcslen(Strings);
}
}
if( AllOptions->NumVendorOptions != nVendorOpts ||
AllOptions->NonVendorOptions->NumElements != nNonVendorOpts ) {
return ERROR_INVALID_DATA;
}
return ERROR_SUCCESS;
}
DWORD
FillOptions( // fill in the optinos..
IN PARRAY OptDefs, // each attrib isz an option to fill in
IN ULONG VendorCount, // # of vendor options
IN ULONG NonVendorCount,// # of non-vendor options
IN ULONG StringSpace, // sapce for strings
IN ULONG BinSpace, // space for binary..
OUT LPDHCP_ALL_OPTIONS AllOptions // fill this in..
)
{
LPBYTE Ptr;
ULONG Size,Result;
LPWSTR Strings;
LPBYTE Binary;
// first comes the structure itself..
AllOptions->Flags = 0;
AllOptions->NumVendorOptions = VendorCount;
Size = ROUND_UP_COUNT(sizeof(*AllOptions), ALIGN_WORST);
Ptr = Size + (LPBYTE)AllOptions;
// next comes NonVendorOptions array
AllOptions->NonVendorOptions = (LPVOID)Ptr;
AllOptions->NonVendorOptions->NumElements = NonVendorCount;
Size += sizeof(*(AllOptions->NonVendorOptions));
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)AllOptions;
if( 0 == NonVendorCount ) {
AllOptions->NonVendorOptions->Options = NULL;
} else {
AllOptions->NonVendorOptions->Options = (LPVOID)Ptr;
}
// Next comes the non-vendor optiosn themselves
Size += NonVendorCount * sizeof(DHCP_OPTION);
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)AllOptions;
// Next comes the vendor options structure..
AllOptions->VendorOptions = (LPVOID)Ptr;
Size += VendorCount * sizeof(*(AllOptions->VendorOptions));
Size = ROUND_UP_COUNT(Size, ALIGN_WORST);
Ptr = Size + (LPBYTE)AllOptions;
// Next store the strings..
Strings = (LPWSTR)Ptr;
Size += sizeof(WCHAR)*StringSpace;
Ptr = Size + (LPBYTE)AllOptions;
// Next store the binary information..
Binary = Ptr;
return AddSpecificOptions(
AllOptions,
Strings,
Binary,
OptDefs
);
}
//BeginExport(function)
//DOC This function retrieves all the optiosn defined for this server.. frm the DS
DWORD
DhcpDsGetAllOptions(
IN LPSTORE_HANDLE hDhcpC,
IN LPSTORE_HANDLE hServer,
IN DWORD Reserved,
OUT LPDHCP_ALL_OPTIONS *Options
) //EndExport(function)
{
DWORD Result, Result2, unused, Size, Size2, i, AllocSize;
ARRAY OptDefAttribs;
PEATTRIB ThisAttrib;
EATTRIB DummyAttrib;
ARRAY_LOCATION Loc;
LPDHCP_OPTION_ARRAY OptArray;
ULONG StringSpace, BinSpace;
ULONG VendorCount, NonVendorCount;
*Options = NULL;
MemArrayInit(&OptDefAttribs);
Result = DhcpDsGetLists( // get list of opt defs frm DS
/* Reserved */ DDS_RESERVED_DWORD,
/* hStore */ hServer,
/* RecursionDepth */ 0xFFFFFFFF,
/* Servers */ NULL,
/* Subnets */ NULL,
/* IpAddress */ NULL,
/* Mask */ NULL,
/* Ranges */ NULL,
/* Sites */ NULL,
/* Reservations */ NULL,
/* SuperScopes */ NULL,
/* OptionDescription */ &OptDefAttribs,
/* OptionsLocation */ NULL,
/* Options */ NULL,
/* Classes */ NULL
);
if( ERROR_SUCCESS != Result ) return Result;
StringSpace = 0; BinSpace = 0;
VendorCount = NonVendorCount = 0;
for( Result = MemArrayInitLoc(&OptDefAttribs, &Loc)
; ERROR_FILE_NOT_FOUND != Result ; // search for optdef w/ <OptId>
Result = MemArrayNextLoc(&OptDefAttribs, &Loc)
) {
Result = MemArrayGetElement(&OptDefAttribs, &Loc, &ThisAttrib);
//- ERROR_SUCCESS == Result && NULL != ThisAttrib
if( !IS_STRING1_PRESENT(ThisAttrib) || !IS_BINARY1_PRESENT(ThisAttrib)
|| !IS_DWORD1_PRESENT(ThisAttrib) ) { // invalid attrib
continue; // skip it
}
Result = ClassifyAndAddOption(
ThisAttrib, &StringSpace, &BinSpace, &VendorCount, &NonVendorCount
);
if( ERROR_SUCCESS != Result ) goto Cleanup;
}
Size = CalculateOptionsSize(
VendorCount, NonVendorCount, StringSpace, BinSpace
);
(*Options) = MemAlloc(Size);
if( NULL == (*Options) ) {
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Result = FillOptions(
&OptDefAttribs, VendorCount, NonVendorCount, StringSpace, BinSpace,
(*Options)
);
if( ERROR_SUCCESS == Result ) return ERROR_SUCCESS;
MemFree(*Options);
*Options = NULL;
Cleanup:
MemArrayFree(&OptDefAttribs, MemFreeFunc);
return Result;
}
//================================================================================
// End of file
//================================================================================