//================================================================================ // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //================================================================================ // 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/ 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/ 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/ 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/ 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/ 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/ 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/ 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/ 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/ 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 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/ 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 //================================================================================