3360 lines
129 KiB
C
3360 lines
129 KiB
C
//================================================================================
|
|
// 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>
|
|
#include <delete.h>
|
|
#include <st_srvr.h>
|
|
#include <upndown.h>
|
|
#include <dnsapi.h>
|
|
|
|
|
|
//================================================================================
|
|
// helper functions
|
|
//================================================================================
|
|
|
|
#include <rpcapi2.h>
|
|
|
|
//
|
|
// Allow Debug prints to ntsd or kd
|
|
//
|
|
|
|
// #ifdef DBG
|
|
// #define DsAuthPrint(_x_) DsAuthDebugPrintRoutine _x_
|
|
|
|
// #else
|
|
// #define DebugPrint(_x_)
|
|
// #endif
|
|
|
|
|
|
extern LPWSTR
|
|
CloneString( IN LPWSTR String );
|
|
|
|
typedef enum {
|
|
LDAP_OPERATOR_EQUAL_TO,
|
|
LDAP_OPERATOR_APPROX_EQUAL_TO,
|
|
LDAP_OPERATOR_LESS_OR_EQUAL_TO,
|
|
LDAP_OPERATOR_GREATER_OR_EQUAL_TO,
|
|
LDAP_OPERATOR_AND,
|
|
LDAP_OPERATOR_OR,
|
|
LDAP_OPERATOR_NOT,
|
|
|
|
LDAP_OPERATOR_TOTAL
|
|
} LDAP_OPERATOR_ENUM;
|
|
|
|
LPWSTR LdapOperators[ LDAP_OPERATOR_TOTAL ] =
|
|
{ L"=", L"~=", L"<=", L">=", L"&", L"|", L"!" };
|
|
|
|
|
|
VOID DsAuthPrintRoutine(
|
|
LPWSTR Format,
|
|
...
|
|
)
|
|
{
|
|
WCHAR buf[2 * 256];
|
|
va_list arg;
|
|
DWORD len;
|
|
|
|
va_start( arg, Format );
|
|
len = wsprintf(buf, L"DSAUTH: ");
|
|
wvsprintf( &buf[ len ], Format, arg );
|
|
|
|
va_end( arg );
|
|
|
|
OutputDebugString( buf );
|
|
} // DsAuthPrint()
|
|
|
|
//
|
|
// This function creates an LDAP query filter string
|
|
// with the option type, value and operator.
|
|
//
|
|
// Syntax:
|
|
// primitive : <filter>=(<attribute><operator><value>)
|
|
// complex : (<operator><filter1><filter2>)
|
|
//
|
|
|
|
LPWSTR
|
|
MakeLdapFilter(
|
|
IN LPWSTR Operand1,
|
|
IN LDAP_OPERATOR_ENUM Operator,
|
|
IN LPWSTR Operand2,
|
|
IN BOOL Primitive
|
|
)
|
|
{
|
|
LPWSTR Result;
|
|
DWORD Size;
|
|
DWORD Len;
|
|
|
|
CHAR buffer[100];
|
|
|
|
Result = NULL;
|
|
|
|
AssertRet((( NULL != Operand1 ) &&
|
|
( NULL != Operand2 ) &&
|
|
(( Operator >= 0 ) && ( Operator < LDAP_OPERATOR_TOTAL ))),
|
|
NULL );
|
|
|
|
// calculate the amount of memory needed
|
|
Size = 0;
|
|
Size += ROUND_UP_COUNT( sizeof( L"(" ), ALIGN_WORST );
|
|
Size += ROUND_UP_COUNT( sizeof( L")" ), ALIGN_WORST );
|
|
Size += ROUND_UP_COUNT( wcslen( Operand1 ), ALIGN_WORST );
|
|
Size += ROUND_UP_COUNT( wcslen( Operand2 ), ALIGN_WORST );
|
|
Size += ROUND_UP_COUNT( wcslen( LdapOperators[ Operator ] ), ALIGN_WORST );
|
|
Size += 16; // padding
|
|
|
|
Result = MemAlloc( Size * sizeof( WCHAR ));
|
|
if ( NULL == Result ) {
|
|
return NULL;
|
|
}
|
|
|
|
if ( Primitive ) {
|
|
Len = wsprintf( Result,
|
|
L"(%ws%ws%ws)",
|
|
Operand1, LdapOperators[ Operator ], Operand2
|
|
);
|
|
}
|
|
else {
|
|
Len = wsprintf( Result,
|
|
L"(%ws%ws%ws)",
|
|
LdapOperators[ Operator ], Operand1, Operand2
|
|
);
|
|
|
|
} // else
|
|
|
|
AssertRet( Len <= Size, NULL );
|
|
|
|
return Result;
|
|
} // MakeLdapFilter()
|
|
|
|
//
|
|
// Make a LDAP query filter like this:
|
|
// (&(objectCategory=dHCPClass)(|(dhcpServer="i<ip>*")(dhcpServer="*s<hostname>*")))
|
|
//
|
|
|
|
LPWSTR
|
|
MakeFilter(
|
|
LPWSTR LookupServerIP, // Printable IP addr
|
|
LPWSTR HostName
|
|
)
|
|
{
|
|
LPWSTR Filter1, Filter2, Filter3, Filter4, SearchFilter;
|
|
LPWSTR Buf;
|
|
DWORD Len, CopiedLen;
|
|
|
|
AssertRet((( NULL != LookupServerIP ) &&
|
|
( NULL != HostName )), NULL );
|
|
|
|
Filter1 = NULL;
|
|
Filter2 = NULL;
|
|
Filter3 = NULL;
|
|
Filter4 = NULL;
|
|
SearchFilter = NULL;
|
|
|
|
do {
|
|
|
|
Len = wcslen( HostName ) + 10 ;
|
|
Buf = MemAlloc( Len * sizeof( WCHAR ));
|
|
if ( NULL == Buf ) {
|
|
break;
|
|
}
|
|
|
|
// make (objectCategory=dHCPClass)
|
|
Filter1 = MakeLdapFilter( ATTRIB_OBJECT_CATEGORY,
|
|
LDAP_OPERATOR_EQUAL_TO,
|
|
DEFAULT_DHCP_CLASS_ATTRIB_VALUE,
|
|
TRUE );
|
|
|
|
if ( NULL == Filter1 ) {
|
|
break;
|
|
}
|
|
|
|
// The IP needs to be sent as i<ip>* to match the query
|
|
|
|
// make (dhcpServers="i<ip>*")
|
|
CopiedLen = _snwprintf( Buf, Len, L"i%ws*", LookupServerIP );
|
|
Require( CopiedLen > 0 );
|
|
Filter2 = MakeLdapFilter( DHCP_ATTRIB_SERVERS,
|
|
LDAP_OPERATOR_EQUAL_TO, Buf, TRUE );
|
|
if ( NULL == Filter2 ) {
|
|
break;
|
|
}
|
|
|
|
// make (dhcpServers="*s<hostname>*")
|
|
CopiedLen = _snwprintf( Buf, Len, L"*s%ws*", HostName );
|
|
Require( CopiedLen > 0 );
|
|
Filter3 = MakeLdapFilter( DHCP_ATTRIB_SERVERS,
|
|
LDAP_OPERATOR_EQUAL_TO, Buf, TRUE );
|
|
|
|
if ( NULL == Filter3 ) {
|
|
break;
|
|
}
|
|
|
|
// make (|(<ipfilter>)(<hostfilter))
|
|
Filter4 = MakeLdapFilter( Filter2, LDAP_OPERATOR_OR,
|
|
Filter3, FALSE );
|
|
|
|
if ( NULL == Filter4 ) {
|
|
break;
|
|
}
|
|
|
|
// Finally make the filter to be returned
|
|
SearchFilter = MakeLdapFilter( Filter1, LDAP_OPERATOR_AND,
|
|
Filter4, FALSE );
|
|
|
|
} while ( FALSE );
|
|
|
|
if ( NULL != Buf ) {
|
|
MemFree( Buf );
|
|
}
|
|
if ( NULL != Filter1 ) {
|
|
MemFree( Filter1 );
|
|
}
|
|
if ( NULL != Filter2 ) {
|
|
MemFree( Filter2 );
|
|
}
|
|
if ( NULL != Filter3 ) {
|
|
MemFree( Filter3 );
|
|
}
|
|
if ( NULL != Filter4 ) {
|
|
MemFree( Filter4 );
|
|
}
|
|
|
|
return SearchFilter;
|
|
} // MakeFilter()
|
|
|
|
//================================================================================
|
|
// This function computes the unique identifier for a client; this is just
|
|
// client subnet + client hw address type + client hw address. note that client
|
|
// hardware address type is hardcoded as HARDWARE_TYPE_10MB_EITHERNET as there
|
|
// is no way in the ui to specify type of reservations..
|
|
// Also, DhcpValidateClient (cltapi.c?) uses the subnet address for validation.
|
|
// Dont remove that.
|
|
//================================================================================
|
|
DWORD
|
|
DhcpMakeClientUID( // compute unique identifier for the client
|
|
IN LPBYTE ClientHardwareAddress,
|
|
IN DWORD ClientHardwareAddressLength,
|
|
IN BYTE ClientHardwareAddressType,
|
|
IN DHCP_IP_ADDRESS ClientSubnetAddress,
|
|
OUT LPBYTE *ClientUID, // will be allocated by function
|
|
OUT DWORD *ClientUIDLength
|
|
)
|
|
{
|
|
LPBYTE Buffer;
|
|
LPBYTE ClientUIDBuffer;
|
|
BYTE ClientUIDBufferLength;
|
|
|
|
if( NULL == ClientUID || NULL == ClientUIDLength || 0 == ClientHardwareAddressLength )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// see comment about on hardcoded hardware address type
|
|
ClientHardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET;
|
|
|
|
ClientUIDBufferLength = sizeof(ClientSubnetAddress);
|
|
ClientUIDBufferLength += sizeof(ClientHardwareAddressType);
|
|
ClientUIDBufferLength += (BYTE)ClientHardwareAddressLength;
|
|
|
|
ClientUIDBuffer = MemAlloc( ClientUIDBufferLength );
|
|
|
|
if( ClientUIDBuffer == NULL ) {
|
|
*ClientUIDLength = 0;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Buffer = ClientUIDBuffer;
|
|
RtlCopyMemory(Buffer,&ClientSubnetAddress,sizeof(ClientSubnetAddress));
|
|
|
|
Buffer += sizeof(ClientSubnetAddress);
|
|
RtlCopyMemory(Buffer,&ClientHardwareAddressType,sizeof(ClientHardwareAddressType) );
|
|
|
|
Buffer += sizeof(ClientHardwareAddressType);
|
|
RtlCopyMemory(Buffer,ClientHardwareAddress,ClientHardwareAddressLength );
|
|
|
|
*ClientUID = ClientUIDBuffer;
|
|
*ClientUIDLength = ClientUIDBufferLength;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
VOID static
|
|
MemFreeFunc( // free memory
|
|
IN OUT LPVOID Memory
|
|
)
|
|
{
|
|
MemFree(Memory);
|
|
}
|
|
|
|
//DOC ServerAddAddress should add the new address to the server's attribs
|
|
//DOC it should take this opportunity to reconcile the server.
|
|
//DOC Currently it does nothing. (at the least it should probably try to
|
|
//DOC check if the object exists, and if not create it.)
|
|
//DOC
|
|
DWORD
|
|
ServerAddAddress( // add server and do misc work
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for server obj
|
|
IN LPWSTR ServerName, // [DNS?] name of server
|
|
IN LPWSTR ADsPath, // ADS path of the server
|
|
IN DWORD IpAddress, // IpAddress to add to server
|
|
IN DWORD State // state of server
|
|
)
|
|
{
|
|
return AddServer(hDhcpC, ServerName, ADsPath, IpAddress, State);
|
|
}
|
|
|
|
//DOC CreateServerObject creates the server object in the DS. It takes the
|
|
//DOC ServerName parameter and names the object using this.
|
|
//DOC The server is created with default values for most attribs.
|
|
//DOC Several attribs are just not set.
|
|
//DOC This returns ERROR_DDS_UNEXPECTED_ERROR if any DS operation fails.
|
|
DWORD
|
|
CreateServerObject( // create dhcp srvr obj in ds
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container to creat obj in
|
|
IN LPWSTR ServerName // [DNS?] name of server
|
|
)
|
|
{
|
|
DWORD Err;
|
|
LPWSTR ServerCNName; // container name
|
|
|
|
ServerCNName = MakeColumnName(ServerName); // convert from "name" to "CN=name"
|
|
if( NULL == ServerCNName ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
Err = StoreCreateObject // now create the object
|
|
(
|
|
/* hStore */ hDhcpC,
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* NewObjName */ ServerCNName,
|
|
/* ... */
|
|
/* Identification */
|
|
ADSTYPE_DN_STRING, ATTRIB_DN_NAME, ServerName,
|
|
ADSTYPE_DN_STRING, ATTRIB_OBJECT_CLASS, DEFAULT_DHCP_CLASS_ATTRIB_VALUE,
|
|
|
|
/* systemMustContain */
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_UNIQUE_KEY, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_TYPE, DHCP_OBJ_TYPE_SERVER,
|
|
ADSTYPE_DN_STRING, ATTRIB_DHCP_IDENTIFICATION, DHCP_OBJ_TYPE_SERVER_DESC,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_FLAGS, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_INSTANCE_TYPE, DEFAULT_INSTANCE_TYPE_ATTRIB_VALUE,
|
|
|
|
/* terminator */
|
|
ADSTYPE_INVALID
|
|
);
|
|
if( ERROR_ALREADY_EXISTS == Err ) { // if object exists, ignore this..
|
|
Err = ERROR_SUCCESS;
|
|
}
|
|
|
|
MemFree(ServerCNName);
|
|
return Err;
|
|
}
|
|
|
|
//DOC CreateSubnetObject creates the subnet object in the DS by cooking up a
|
|
//DOC name that is just a concatenation of the server name and the subnet address.
|
|
//DOC The object is set with some default values for most attribs.
|
|
//DOC This fn returns ERROR_DDS_UNEXPECTED_ERROR if any DS operation fails.
|
|
DWORD
|
|
CreateSubnetObject( // create dhcp subnet obj in ds
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container obj
|
|
IN LPWSTR SubnetCNName // subnet name in "CN=xx" fmt
|
|
)
|
|
{
|
|
DWORD Err;
|
|
LPWSTR SubnetName;
|
|
|
|
SubnetName = SubnetCNName + 3; // skip the "CN=" part
|
|
|
|
Err = StoreCreateObject // now create the object
|
|
(
|
|
/* hStore */ hDhcpC,
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* NewObjName */ SubnetCNName,
|
|
/* ... */
|
|
/* Identification */
|
|
ADSTYPE_DN_STRING, ATTRIB_DN_NAME, SubnetName,
|
|
ADSTYPE_DN_STRING, ATTRIB_OBJECT_CLASS, DEFAULT_DHCP_CLASS_ATTRIB_VALUE,
|
|
|
|
/* systemMustContain */
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_UNIQUE_KEY, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_TYPE, DHCP_OBJ_TYPE_SUBNET,
|
|
ADSTYPE_DN_STRING, ATTRIB_DHCP_IDENTIFICATION, DHCP_OBJ_TYPE_SUBNET_DESC,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_FLAGS, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_INSTANCE_TYPE, DEFAULT_INSTANCE_TYPE_ATTRIB_VALUE,
|
|
|
|
/* terminator */
|
|
ADSTYPE_INVALID
|
|
);
|
|
if( ERROR_ALREADY_EXISTS == Err ) { // if object exists, ignore this..
|
|
Err = ERROR_SUCCESS;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
//DOC CreateReservationObject creates a reservation object in the DS.
|
|
//DOC It just fills in some reasonable information for all the required fields.
|
|
//DOC If fails if the object already exists
|
|
//DOC
|
|
DWORD
|
|
CreateReservationObject( // create reservation object in DS
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container obj
|
|
IN LPWSTR ReserveCNName // reservation name in "CN=X" fmt
|
|
)
|
|
{
|
|
DWORD Err;
|
|
LPWSTR ReserveName;
|
|
|
|
ReserveName = ReserveCNName+ 3;
|
|
|
|
Err = StoreCreateObject // now create the object
|
|
(
|
|
/* hStore */ hDhcpC,
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* NewObjName */ ReserveCNName,
|
|
/* ... */
|
|
/* Identification */
|
|
ADSTYPE_DN_STRING, ATTRIB_DN_NAME, ReserveName,
|
|
ADSTYPE_DN_STRING, ATTRIB_OBJECT_CLASS, DEFAULT_DHCP_CLASS_ATTRIB_VALUE,
|
|
|
|
/* systemMustContain */
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_UNIQUE_KEY, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_TYPE, DHCP_OBJ_TYPE_RESERVATION,
|
|
ADSTYPE_DN_STRING, ATTRIB_DHCP_IDENTIFICATION, DHCP_OBJ_TYPE_RESERVATION_DESC,
|
|
ADSTYPE_INTEGER, ATTRIB_DHCP_FLAGS, 0,
|
|
ADSTYPE_INTEGER, ATTRIB_INSTANCE_TYPE, DEFAULT_INSTANCE_TYPE_ATTRIB_VALUE,
|
|
|
|
/* terminator */
|
|
ADSTYPE_INVALID
|
|
);
|
|
if( ERROR_ALREADY_EXISTS == Err ) { // if object exists, ignore this..
|
|
Err = ERROR_SUCCESS;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
//DOC FindCollisions walks through an array of attribs and compares each
|
|
//DOC against the parameters to see if there is a collision.. If the parameters
|
|
//DOC passed have type RANGE, then an extension of a range is allowed.
|
|
//DOC If not, anything is allowed. In case there is an extension, the Extender
|
|
//DOC parameter is filled with the attrib that gets extended..
|
|
//DOC This function returns TRUE if there is a collision and FALSE if ok.
|
|
BOOL
|
|
FindCollisions( // find range vs range collisions
|
|
IN PARRAY Attribs, // array of PEATTRIB's
|
|
IN DWORD RangeStart,
|
|
IN DWORD RangeEnd,
|
|
IN DWORD RangeType, // RANGE_TYPE_RANGE || RANGE_TYPE_EXCL
|
|
OUT PEATTRIB *Extender // this attrib needs to be extended
|
|
)
|
|
{
|
|
DWORD Err, Cond;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
|
|
*Extender = NULL;
|
|
if( (RangeType & RANGE_TYPE_MASK) == RANGE_TYPE_EXCL ) {
|
|
return ERROR_SUCCESS; // anything is ok for excl
|
|
}
|
|
|
|
for( // walk thru the array
|
|
Err = MemArrayInitLoc(Attribs, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(Attribs, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(Attribs, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no range start
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) || // no range end
|
|
!IS_FLAGS1_PRESENT(ThisAttrib) ) { // range state?
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( IS_FLAGS2_PRESENT(ThisAttrib) &&
|
|
(RANGE_TYPE_MASK & ThisAttrib->Flags2) == RANGE_TYPE_EXCL ) {
|
|
continue; // skip exclusions
|
|
}
|
|
|
|
if( ThisAttrib->Address2 < ThisAttrib->Address1 ) {
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
Cond = MemRangeCompare(
|
|
RangeStart,RangeEnd, // range X and below is range Y
|
|
ThisAttrib->Address1, ThisAttrib->Address2
|
|
);
|
|
switch(Cond) { // make comparisons on 2 ranges
|
|
case X_LESSTHAN_Y_OVERLAP:
|
|
case Y_LESSTHAN_X_OVERLAP:
|
|
if( NULL != *Extender ) return TRUE; // double extensions not allowed
|
|
*Extender = ThisAttrib;
|
|
break;
|
|
case X_IN_Y:
|
|
case Y_IN_X:
|
|
return TRUE; // head on collision is fatal
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
ServerMatched(
|
|
IN PEATTRIB ThisAttrib,
|
|
IN LPWSTR ServerName,
|
|
IN ULONG IpAddress,
|
|
OUT BOOL *fExactMatch
|
|
)
|
|
{
|
|
BOOL fIpMatch, fNameMatch, fWildcardIp;
|
|
|
|
(*fExactMatch) = FALSE;
|
|
|
|
fIpMatch = (ThisAttrib->Address1 == IpAddress);
|
|
if( INADDR_BROADCAST == ThisAttrib->Address1 ||
|
|
INADDR_BROADCAST == IpAddress ) {
|
|
fWildcardIp = TRUE;
|
|
} else {
|
|
fWildcardIp = FALSE;
|
|
}
|
|
|
|
if( FALSE == fIpMatch ) {
|
|
//
|
|
// If IP Addresses don't match, then check to see if
|
|
// one of the IP addresses is a broadcast address..
|
|
//
|
|
if( !fWildcardIp ) return FALSE;
|
|
}
|
|
|
|
fNameMatch = DnsNameCompare_W(ThisAttrib->String1, ServerName);
|
|
if( FALSE == fNameMatch ) {
|
|
//
|
|
// If names don't match _and_ IP's don't match, no match.
|
|
//
|
|
if( FALSE == fIpMatch || fWildcardIp ) return FALSE;
|
|
} else {
|
|
if( FALSE == fIpMatch ) return TRUE;
|
|
|
|
(*fExactMatch) = TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
GetListOfAllServersMatchingFilter(
|
|
IN OUT LPSTORE_HANDLE hDhcpC,
|
|
IN OUT PARRAY Servers,
|
|
IN LPWSTR SearchFilter OPTIONAL
|
|
)
|
|
{
|
|
DWORD Err, LastErr;
|
|
STORE_HANDLE hContainer;
|
|
LPWSTR Filter;
|
|
|
|
AssertRet( ( NULL != hDhcpC ) && ( NULL != Servers ),
|
|
ERROR_INVALID_PARAMETER );
|
|
|
|
Err = StoreSetSearchOneLevel(
|
|
hDhcpC, DDS_RESERVED_DWORD );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
if ( NULL == SearchFilter ) {
|
|
Filter = DHCP_SEARCH_FILTER;
|
|
}
|
|
else {
|
|
Filter = SearchFilter;
|
|
}
|
|
AssertRet( NULL != Filter, ERROR_INVALID_PARAMETER );
|
|
|
|
Err = StoreBeginSearch(
|
|
hDhcpC, DDS_RESERVED_DWORD, Filter );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
while( TRUE ) {
|
|
Err = StoreSearchGetNext(
|
|
hDhcpC, DDS_RESERVED_DWORD, &hContainer );
|
|
|
|
if( ERROR_DS_INVALID_DN_SYNTAX == Err ) {
|
|
//
|
|
// This nasty problem is because of an upgrade issue
|
|
// in DS where some bad-named objects may exist..
|
|
//
|
|
Err = NO_ERROR;
|
|
continue;
|
|
}
|
|
|
|
if( NO_ERROR != Err ) break;
|
|
|
|
Err = DhcpDsGetLists
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ &hContainer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ Servers, // array of PEATTRIB 's
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
StoreCleanupHandle( &hContainer, DDS_RESERVED_DWORD );
|
|
|
|
if( NO_ERROR != Err ) break;
|
|
|
|
}
|
|
|
|
if( Err == ERROR_NO_MORE_ITEMS ) Err = NO_ERROR;
|
|
|
|
LastErr = StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD );
|
|
//Require( LastErr == NO_ERROR );
|
|
|
|
return Err;
|
|
}
|
|
|
|
DWORD
|
|
DhcpDsAddServerInternal( // add a server in DS
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, future use
|
|
IN LPWSTR ServerName, // [DNS?] name of server
|
|
IN LPWSTR ReservedPtr, // Server location? future use
|
|
IN DWORD IpAddress, // ip address of server
|
|
IN DWORD State // currently un-interpreted
|
|
)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
EATTRIB DummyAttrib;
|
|
BOOL fServerExists;
|
|
LPWSTR ServerLocation, Tmp;
|
|
DWORD ServerLocType;
|
|
|
|
if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Servers); // cant fail
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of servers
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hDhcpRoot,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ &Servers, // array of PEATTRIB 's
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Tmp = NULL; ServerLocation = NULL;
|
|
fServerExists = FALSE; // did we find the same servername?
|
|
for( // search list of servers
|
|
Err = MemArrayInitLoc(&Servers, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element
|
|
) {
|
|
BOOL fExactMatch = FALSE;
|
|
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) {
|
|
//
|
|
// Server found in the list of servers. Exact match not allowed.
|
|
//
|
|
if( fExactMatch ) {
|
|
MemArrayFree(&Servers,MemFreeFunc);// free allocated memory
|
|
return ERROR_DDS_SERVER_ALREADY_EXISTS;
|
|
}
|
|
|
|
fServerExists = TRUE;
|
|
if( IS_ADDRESS1_PRESENT(ThisAttrib) &&
|
|
NULL == ServerLocation ) { // remember location in DS.
|
|
ServerLocation = ThisAttrib->ADsPath;
|
|
ServerLocType = ThisAttrib->StoreGetType;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if( !fServerExists ) { // if freshly adding a server, create obj
|
|
WCHAR Buf[sizeof("000.000.000.000")];
|
|
LPWSTR SName;
|
|
|
|
if( L'\0' != ServerName[0] ) {
|
|
SName = ServerName;
|
|
} else {
|
|
ULONG IpAddr;
|
|
LPSTR IpAddrString;
|
|
|
|
IpAddr = htonl(IpAddress);
|
|
IpAddrString = inet_ntoa(*(struct in_addr *)&IpAddr);
|
|
Err = mbstowcs(Buf, IpAddrString, sizeof(Buf)/sizeof(WCHAR));
|
|
if( -1 == Err ) {
|
|
MemArrayFree(&Servers, MemFreeFunc);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
SName = Buf;
|
|
}
|
|
|
|
ServerLocation = Tmp = MakeColumnName(SName);
|
|
ServerLocType = StoreGetChildType;
|
|
}
|
|
|
|
NothingPresent(&DummyAttrib); // fill in attrib w/ srvr info
|
|
STRING1_PRESENT(&DummyAttrib); // name
|
|
ADDRESS1_PRESENT(&DummyAttrib); // ip addr
|
|
FLAGS1_PRESENT(&DummyAttrib); // state
|
|
DummyAttrib.String1 = ServerName;
|
|
DummyAttrib.Address1 = IpAddress;
|
|
DummyAttrib.Flags1 = State;
|
|
if( ServerLocation ) {
|
|
ADSPATH_PRESENT(&DummyAttrib); // ADsPath of location of server object
|
|
STOREGETTYPE_PRESENT(&DummyAttrib);
|
|
DummyAttrib.ADsPath = ServerLocation;
|
|
DummyAttrib.StoreGetType = ServerLocType;
|
|
}
|
|
|
|
Err = MemArrayAddElement(&Servers, &DummyAttrib);
|
|
if( ERROR_SUCCESS != Err ) { // could not add this to attrib array
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
if( Tmp ) MemFree(Tmp); // if allocate mem for ServerLocation..
|
|
return Err;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // now set the new attrib list
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hDhcpRoot,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ &Servers,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
Err2 = MemArrayLastLoc(&Servers, &Loc); // theres atleast 1 elt in array
|
|
//= require ERROR_SUCCESS == Err2
|
|
Err2 = MemArrayDelElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err2 && ThisAttrib == &DummyAttrib
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
|
|
if( ERROR_SUCCESS != Err || fServerExists ) {
|
|
if( Tmp ) MemFree(Tmp); // if allocated memory for ServerLocation..
|
|
if( ERROR_SUCCESS != Err) return Err; // check err for DhcpDsSetLists
|
|
|
|
//: This wont do if there is a problem...
|
|
if( fServerExists ) return ERROR_SUCCESS; // if server already existed.. not much work needed?
|
|
}
|
|
|
|
if( Tmp ) MemFree(Tmp);
|
|
|
|
return Err;
|
|
}
|
|
|
|
//================================================================================
|
|
// exported functions
|
|
//================================================================================
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsAddServer adds a server's entry in the DS. Note that only the name
|
|
//DOC uniquely determines the server. There can be one server with many ip addresses.
|
|
//DOC If the server is created first time, a separate object is created for the
|
|
//DOC server. : TO DO: The newly added server should also have its data
|
|
//DOC updated in the DS uploaded from the server itself if it is still up.
|
|
//DOC Note that it takes as parameter the Dhcp root container.
|
|
//DOC If the requested address already exists in the DS (maybe to some other
|
|
//DOC server), then the function returns ERROR_DDS_SERVER_ALREADY_EXISTS
|
|
DWORD
|
|
DhcpDsAddServer( // add a server in DS
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, future use
|
|
IN LPWSTR ServerName, // [DNS?] name of server
|
|
IN LPWSTR ReservedPtr, // Server location? future use
|
|
IN DWORD IpAddress, // ip address of server
|
|
IN DWORD State // currently un-interpreted
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
BOOL fServerExists;
|
|
LPWSTR ServerLocation, Tmp;
|
|
DWORD ServerLocType;
|
|
STORE_HANDLE hDhcpServer;
|
|
|
|
if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Servers); // cant fail
|
|
//= require ERROR_SUCCESS == Err
|
|
|
|
DsAuthPrint(( L"DhcpAddServer() \n" ));
|
|
|
|
Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers,
|
|
DHCP_SEARCH_FILTER );
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Tmp = NULL; ServerLocation = NULL;
|
|
fServerExists = FALSE; // did we find the same servername?
|
|
for( // search list of servers
|
|
Err = MemArrayInitLoc(&Servers, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element
|
|
) {
|
|
BOOL fExactMatch = FALSE;
|
|
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) {
|
|
//
|
|
// Server found in the list of servers. Exact match not allowed.
|
|
//
|
|
if( fExactMatch ) {
|
|
MemArrayFree(&Servers,MemFreeFunc);// free allocated memory
|
|
return ERROR_DDS_SERVER_ALREADY_EXISTS;
|
|
}
|
|
|
|
fServerExists = TRUE;
|
|
if( IS_ADDRESS1_PRESENT(ThisAttrib) &&
|
|
NULL == ServerLocation ) { // remember location in DS.
|
|
ServerLocation = ThisAttrib->ADsPath;
|
|
ServerLocType = ThisAttrib->StoreGetType;
|
|
}
|
|
}
|
|
} // for
|
|
|
|
if( !fServerExists ) { // if freshly adding a server, create obj
|
|
WCHAR Buf[sizeof("000.000.000.000")];
|
|
LPWSTR SName;
|
|
|
|
if( L'\0' != ServerName[0] ) {
|
|
// do not use the name. Use the printable IP addr instead
|
|
SName = ServerName;
|
|
} else {
|
|
ULONG IpAddr;
|
|
LPSTR IpAddrString;
|
|
|
|
IpAddr = htonl(IpAddress);
|
|
IpAddrString = inet_ntoa(*(struct in_addr *)&IpAddr);
|
|
Err = mbstowcs(Buf, IpAddrString, sizeof(Buf)/sizeof(WCHAR));
|
|
if( -1 == Err ) {
|
|
MemArrayFree(&Servers, MemFreeFunc);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
SName = Buf;
|
|
}
|
|
|
|
Err = CreateServerObject(
|
|
/* hDhcpC */ hDhcpC,
|
|
/* ServerName */ SName
|
|
);
|
|
if( ERROR_SUCCESS != Err ) { // dont add server if obj cant be created
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
return Err;
|
|
}
|
|
ServerLocation = Tmp = MakeColumnName(SName);
|
|
ServerLocType = StoreGetChildType;
|
|
}
|
|
|
|
Err = StoreGetHandle(
|
|
hDhcpC, 0, ServerLocType, ServerLocation, &hDhcpServer );
|
|
if( NO_ERROR == Err ) {
|
|
Err = DhcpDsAddServerInternal(
|
|
hDhcpC, &hDhcpServer, Reserved, ServerName, ReservedPtr,
|
|
IpAddress, State );
|
|
StoreCleanupHandle( &hDhcpServer, 0 );
|
|
}
|
|
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
|
|
if( ERROR_SUCCESS != Err || fServerExists ) {
|
|
if( Tmp ) MemFree(Tmp); // if allocated memory for ServerLocation..
|
|
if( ERROR_SUCCESS != Err) return Err; // check err for DhcpDsSetLists
|
|
|
|
//: This wont do if there is a problem...
|
|
if( fServerExists ) return ERROR_SUCCESS; // if server already existed.. not much work needed?
|
|
}
|
|
|
|
Err = ServerAddAddress // add the info into the server
|
|
(
|
|
/* hDhcpC */ hDhcpC,
|
|
/* ServerName */ ServerName,
|
|
/* ADsPath */ ServerLocation,
|
|
/* IpAddress */ IpAddress,
|
|
/* State */ State
|
|
);
|
|
if( Tmp ) MemFree(Tmp);
|
|
|
|
return Err;
|
|
}
|
|
|
|
DWORD
|
|
DhcpDsDelServerInternal( // Delete a server from memory
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
IN LPWSTR ServerName, // which server to delete for
|
|
IN LPWSTR ReservedPtr, // server location ? future use
|
|
IN DWORD IpAddress // the IpAddress to delete..
|
|
)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib, SavedAttrib;
|
|
BOOL fServerExists;
|
|
BOOL fServerDeleted;
|
|
LPWSTR SName;
|
|
LPWSTR ServerLoc = NULL;
|
|
DWORD ServerLocType;
|
|
WCHAR Buf[sizeof("000.000.000.000")];
|
|
|
|
if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Servers); // cant fail
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of servers
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hDhcpRoot,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ &Servers, // array of PEATTRIB 's
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
SavedAttrib = NULL;
|
|
fServerExists = fServerDeleted = FALSE;
|
|
for( // search list of servers
|
|
Err = MemArrayInitLoc(&Servers, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element
|
|
) {
|
|
BOOL fExactMatch = FALSE;
|
|
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) {
|
|
//
|
|
// Server found. If exact match, remove the element from list.
|
|
//
|
|
if( fExactMatch ) {
|
|
Err2 = MemArrayDelElement(&Servers, &Loc, &ThisAttrib);
|
|
//= ERROR_SUCCESS == Err2 && NULL != ThisAttrib
|
|
}
|
|
|
|
if( (NULL == ServerLoc || fExactMatch)
|
|
&& IS_ADSPATH_PRESENT(ThisAttrib) ) {
|
|
ServerLocType = ThisAttrib->StoreGetType;
|
|
ServerLoc = ThisAttrib->ADsPath; // remember this path..
|
|
SavedAttrib = ThisAttrib; // remember this attrib.. to del later
|
|
} else { // this attrib is useless, free it
|
|
if( fExactMatch ) MemFree(ThisAttrib);
|
|
}
|
|
|
|
if( fExactMatch ) fServerDeleted = TRUE;
|
|
else fServerExists = TRUE;
|
|
}
|
|
}
|
|
|
|
if( !fServerDeleted ) { // never found the requested entry..
|
|
MemArrayFree(&Servers, MemFreeFunc); // free up memory
|
|
return ERROR_DDS_SERVER_DOES_NOT_EXIST;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // now set the new attrib list
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hDhcpRoot,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ &Servers,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
if( ERROR_SUCCESS != Err) { // check err for DhcpDsSetLists
|
|
if(SavedAttrib) MemFree(SavedAttrib);
|
|
return Err;
|
|
}
|
|
|
|
if( fServerExists ) { // still some addr left for this srvr
|
|
if( SavedAttrib ) MemFree(SavedAttrib);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
if( SavedAttrib ) MemFree(SavedAttrib);
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsDelServer removes the requested servername-ipaddress pair from the ds.
|
|
//DOC If this is the last ip address for the given servername, then the server
|
|
//DOC is also removed from memory. But objects referred by the Server are left in
|
|
//DOC the DS as they may also be referred to from else where. This needs to be
|
|
//DOC fixed via references being tagged as direct and symbolic -- one causing deletion
|
|
//DOC and other not causing any deletion. THIS NEEDS TO BE FIXED.
|
|
DWORD
|
|
DhcpDsDelServer( // Delete a server from memory
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
IN LPWSTR ServerName, // which server to delete for
|
|
IN LPWSTR ReservedPtr, // server location ? future use
|
|
IN DWORD IpAddress // the IpAddress to delete..
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, LastErr, ReturnError;
|
|
STORE_HANDLE hDhcpServer;
|
|
ARRAY Servers;
|
|
BOOL fEmpty;
|
|
LPWSTR Location;
|
|
LPWSTR IsDhcpRoot = NULL;
|
|
|
|
MemArrayInit(&Servers);
|
|
|
|
Err = StoreSetSearchOneLevel(
|
|
hDhcpC, DDS_RESERVED_DWORD );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
Err = StoreBeginSearch(
|
|
hDhcpC, DDS_RESERVED_DWORD, DHCP_SEARCH_FILTER );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
//
|
|
// Look at each dhcp object in container
|
|
//
|
|
|
|
ReturnError = ERROR_DDS_SERVER_DOES_NOT_EXIST;
|
|
|
|
while( TRUE ) {
|
|
Err = StoreSearchGetNext(
|
|
hDhcpC, DDS_RESERVED_DWORD, &hDhcpServer );
|
|
|
|
if( ERROR_DS_INVALID_DN_SYNTAX == Err ) {
|
|
//
|
|
// This nasty problem is because of an upgrade issue
|
|
// in DS where some bad-named objects may exist..
|
|
//
|
|
Err = NO_ERROR;
|
|
continue;
|
|
}
|
|
|
|
if( NO_ERROR != Err ) break;
|
|
|
|
//
|
|
// Attempt to delete reqd server
|
|
//
|
|
|
|
Err = DhcpDsDelServerInternal(
|
|
hDhcpC, &hDhcpServer, Reserved, ServerName,
|
|
ReservedPtr, IpAddress );
|
|
|
|
if( ERROR_DDS_SERVER_DOES_NOT_EXIST == Err ) {
|
|
StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD );
|
|
continue;
|
|
}
|
|
|
|
if( NO_ERROR != Err ) {
|
|
StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD );
|
|
break;
|
|
}
|
|
|
|
ReturnError = NO_ERROR;
|
|
|
|
//
|
|
// If the above succeeded, then check if the container
|
|
// has no servers defined -- in this case we can delete
|
|
// the container itself
|
|
//
|
|
|
|
Err = DhcpDsGetLists
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ &hDhcpServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ &Servers, // array of PEATTRIB 's
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
if( NO_ERROR != Err ) {
|
|
StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD );
|
|
break;
|
|
}
|
|
|
|
fEmpty = (0 == MemArraySize(&Servers));
|
|
MemArrayFree(&Servers, MemFreeFunc);
|
|
|
|
Location = CloneString(hDhcpServer.Location);
|
|
StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD );
|
|
|
|
if( NULL == Location ) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
IsDhcpRoot = wcsstr( Location, DHCP_ROOT_OBJECT_NAME );
|
|
|
|
if( fEmpty && ( IsDhcpRoot == NULL ) )
|
|
Err = StoreDeleteThisObject(
|
|
hDhcpC,
|
|
DDS_RESERVED_DWORD,
|
|
StoreGetAbsoluteOtherServerType,
|
|
Location );
|
|
|
|
|
|
MemFree( Location );
|
|
|
|
if( NO_ERROR != Err ) break;
|
|
}
|
|
|
|
if( Err == ERROR_NO_MORE_ITEMS ) Err = NO_ERROR;
|
|
|
|
LastErr = StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD );
|
|
//Require( LastErr == NO_ERROR );
|
|
|
|
if( NO_ERROR == Err ) Err = ReturnError;
|
|
|
|
return Err;
|
|
} // DhcpDsDelServer()
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpDsLookupServer( // get info about a server
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
IN LPWSTR LookupServerIP,// Server to lookup IP
|
|
IN LPWSTR HostName // Hostname to lookup
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Size, Size2, i, N;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
LPDHCPDS_SERVERS LocalServers;
|
|
LPBYTE Ptr;
|
|
LPWSTR SearchFilter;
|
|
STORE_HANDLE hContainer;
|
|
|
|
if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params
|
|
return FALSE;
|
|
if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return FALSE;
|
|
|
|
if (( NULL == HostName ) ||
|
|
( NULL == LookupServerIP )) {
|
|
return FALSE;
|
|
}
|
|
|
|
SearchFilter = MakeFilter( LookupServerIP, HostName );
|
|
if ( NULL == SearchFilter ) {
|
|
return FALSE;
|
|
}
|
|
|
|
DsAuthPrint(( L"hostname = %ws, IP = %ws, Filter = %ws\n",
|
|
HostName, LookupServerIP, SearchFilter ));
|
|
|
|
Err = StoreSetSearchOneLevel( hDhcpC, DDS_RESERVED_DWORD );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
Err = StoreBeginSearch( hDhcpC, DDS_RESERVED_DWORD, SearchFilter );
|
|
MemFree( SearchFilter );
|
|
AssertRet( Err == NO_ERROR, Err );
|
|
|
|
Err = StoreSearchGetNext( hDhcpC, DDS_RESERVED_DWORD, &hContainer );
|
|
|
|
StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD );
|
|
return ( NO_ERROR == Err );
|
|
} // DhcpDsLookupServer()
|
|
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsEnumServers retrieves a bunch of information about each server that
|
|
//DOC has an entry in the Servers attribute of the root object. There are no guarantees
|
|
//DOC on the order..
|
|
//DOC The memory for this is allocated in ONE shot -- so the output can be freed in
|
|
//DOC one shot too.
|
|
//DOC
|
|
DWORD
|
|
DhcpDsEnumServers( // get info abt all existing servers
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects
|
|
IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
OUT LPDHCPDS_SERVERS *ServersInfo // array of servers
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Size, Size2, i, N;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
LPDHCPDS_SERVERS LocalServers;
|
|
LPBYTE Ptr;
|
|
LPWSTR Filter1, Filter2, Filter3;
|
|
|
|
if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( 0 != Reserved || NULL == ServersInfo )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
*ServersInfo = NULL; i = N = Size = Size2 = 0;
|
|
|
|
Err = MemArrayInit(&Servers); // cant fail
|
|
//= require ERROR_SUCCESS == Err
|
|
|
|
DsAuthPrint(( L"DhcpDsEnumServers \n" ));
|
|
|
|
Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers,
|
|
DHCP_SEARCH_FILTER );
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Size = Size2 = 0;
|
|
for( // walk thru list of servers
|
|
Err = MemArrayInitLoc(&Servers, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
Size2 = sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1));
|
|
if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // if ADsPath there, account for it
|
|
Size2 += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->ADsPath));
|
|
}
|
|
|
|
Size += Size2; // keep track of total mem reqd
|
|
i ++;
|
|
}
|
|
|
|
Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVERS), ALIGN_WORST);
|
|
Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVER)*i, ALIGN_WORST);
|
|
Ptr = MemAlloc(Size); // allocate memory
|
|
if( NULL == Ptr ) {
|
|
MemArrayFree(&Servers, MemFreeFunc ); // free allocated memory
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
LocalServers = (LPDHCPDS_SERVERS)Ptr;
|
|
LocalServers->NumElements = i;
|
|
LocalServers->Flags = 0;
|
|
Size = 0; // start from offset 0
|
|
Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVERS), ALIGN_WORST);
|
|
LocalServers->Servers = (LPDHCPDS_SERVER)(Size + Ptr);
|
|
Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVER)*i, ALIGN_WORST);
|
|
|
|
i = Size2 = 0;
|
|
for( // copy list of servers
|
|
Err = MemArrayInitLoc(&Servers, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
LocalServers->Servers[i].Version =0; // version is always zero in this build
|
|
LocalServers->Servers[i].State=0;
|
|
LocalServers->Servers[i].ServerName = (LPWSTR)(Size + Ptr);
|
|
wcscpy((LPWSTR)(Size+Ptr), ThisAttrib->String1);
|
|
Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1));
|
|
LocalServers->Servers[i].ServerAddress = ThisAttrib->Address1;
|
|
if( IS_FLAGS1_PRESENT(ThisAttrib) ) { // State present
|
|
LocalServers->Servers[i].Flags = ThisAttrib->Flags1;
|
|
} else {
|
|
LocalServers->Servers[i].Flags = 0; // if no flags present, use zero
|
|
}
|
|
if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // if ADsPath there, copy it too
|
|
LocalServers->Servers[i].DsLocType = ThisAttrib->StoreGetType;
|
|
LocalServers->Servers[i].DsLocation = (LPWSTR)(Size + Ptr);
|
|
wcscpy((LPWSTR)(Size + Ptr), ThisAttrib->ADsPath);
|
|
Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->ADsPath));
|
|
} else { // no ADsPath present
|
|
LocalServers->Servers[i].DsLocType = 0;
|
|
LocalServers->Servers[i].DsLocation = NULL;
|
|
}
|
|
i ++;
|
|
}
|
|
|
|
*ServersInfo = LocalServers;
|
|
MemArrayFree(&Servers, MemFreeFunc ); // free allocated memory
|
|
return ERROR_SUCCESS;
|
|
} // DhcpDsEnumServers()
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsSetSScope modifies the superscope that a subnet belongs to.
|
|
//DOC The function tries to set the superscope of the subnet referred by
|
|
//DOC address IpAddress to SScopeName. It does not matter if the superscope
|
|
//DOC by that name does not exist, it is automatically created.
|
|
//DOC If the subnet already had a superscope, then the behaviour depends on
|
|
//DOC the flag ChangeSScope. If this is TRUE, it sets the new superscopes.
|
|
//DOC If the flag is FALSE, it returns ERROR_DDS_SUBNET_HAS_DIFF_SSCOPE.
|
|
//DOC This flag is ignored if the subnet does not have a superscope already.
|
|
//DOC If SScopeName is NULL, the function removes the subnet from any superscope
|
|
//DOC if it belonged to one before.
|
|
//DOC If the specified subnet does not exist, it returns ERROR_DDS_SUBNET_NOT_PRESENT.
|
|
DWORD
|
|
DhcpDsSetSScope( // change superscope of subnet
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored
|
|
IN OUT LPSTORE_HANDLE hServer, // the server object referred
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
IN DWORD IpAddress, // subnet address to use
|
|
IN LPWSTR SScopeName, // sscope it must now be in
|
|
IN BOOL ChangeSScope // if it already has a SScope, change it?
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, unused;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
BOOL SubnetPresent;
|
|
|
|
if( 0 != Reserved ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer || NULL == hServer->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // fetch subnet array
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail
|
|
|
|
SubnetPresent = FALSE;
|
|
for( // search for specified subnet
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // init
|
|
; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ThisAttrib->Address1 != IpAddress ) { // not this subnet we're looking for
|
|
continue;
|
|
}
|
|
|
|
SubnetPresent = TRUE; // found the subnet we're intersted in
|
|
break;
|
|
}
|
|
|
|
if( !SubnetPresent ) { // did not even find the subnet?
|
|
MemArrayFree(&Subnets, MemFreeFunc); // free up memory taken
|
|
return ERROR_DDS_SUBNET_NOT_PRESENT;
|
|
}
|
|
|
|
if( NULL == SScopeName ) { // we're trying to remove from sscope
|
|
if( !IS_STRING3_PRESENT(ThisAttrib) ) { // does not belong to any sscope ?
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_SUCCESS; // return as no change reqd
|
|
}
|
|
STRING3_ABSENT(ThisAttrib); // remove SScope..
|
|
} else {
|
|
if( IS_STRING3_PRESENT(ThisAttrib) ) { // sscope present.. trying to change it
|
|
if( FALSE == ChangeSScope ) { // we were not asked to do this
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_DDS_SUBNET_HAS_DIFF_SSCOPE;
|
|
}
|
|
}
|
|
|
|
STRING3_PRESENT(ThisAttrib);
|
|
ThisAttrib->String3 = SScopeName; // set the new SScope for this
|
|
}
|
|
|
|
Err = DhcpDsSetLists // now write back the new info onto the DS
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescripti.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescriptio.. */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsDelSScope deletes the superscope and removes all elements
|
|
//DOC that belong to that superscope in one shot. There is no error if the
|
|
//DOC superscope does not exist.
|
|
DWORD
|
|
DhcpDsDelSScope( // delete superscope off DS
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored
|
|
IN OUT LPSTORE_HANDLE hServer, // the server object referred
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
IN LPWSTR SScopeName // sscope to delete
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, unused;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
BOOL AnythingChanged;
|
|
|
|
if( 0 != Reserved || NULL == SScopeName ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer || NULL == hServer->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // fetch subnet array
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail
|
|
|
|
AnythingChanged = FALSE;
|
|
for( // search for specified SScope
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // init
|
|
; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( !IS_STRING3_PRESENT(ThisAttrib) ) { // this subnet does not have a sscope anyways
|
|
continue;
|
|
}
|
|
|
|
if( 0 != wcscmp(ThisAttrib->String3, SScopeName) ) {
|
|
continue; // not the same superscope
|
|
}
|
|
|
|
STRING3_ABSENT(ThisAttrib); // kill the superscope
|
|
AnythingChanged = TRUE;
|
|
}
|
|
|
|
if( !AnythingChanged ) {
|
|
Err = ERROR_SUCCESS; // nothing more to do now..
|
|
} else {
|
|
Err = DhcpDsSetLists // now write back the new info onto the DS
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescripti..*/ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescriptio..*/ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
}
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsGetSScopeInfo retrieves the SuperScope table for the server of interest.
|
|
//DOC The table itself is allocated in one blob, so it can be freed lateron.
|
|
//DOC The SuperScopeNumber is garbage (always zero) and the NextInSuperScope reflects
|
|
//DOC the order in the DS which may/maynot be the same in the DHCP server.
|
|
//DOC SuperScopeName is NULL in for subnets that done have a sscope.
|
|
DWORD
|
|
DhcpDsGetSScopeInfo( // get superscope table from ds
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored
|
|
IN OUT LPSTORE_HANDLE hServer, // the server object referred
|
|
IN DWORD Reserved, // must be zero, for future use
|
|
OUT LPDHCP_SUPER_SCOPE_TABLE *SScopeTbl // allocated by this func in one blob
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, unused, Size, Size2, i;
|
|
DWORD Index, nSubnets;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
LPDHCP_SUPER_SCOPE_TABLE LocalTbl;
|
|
LPBYTE Ptr;
|
|
|
|
if( 0 != Reserved ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer || NULL == hServer->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == SScopeTbl ) return ERROR_INVALID_PARAMETER;
|
|
|
|
*SScopeTbl = NULL;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // fetch subnet array
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail
|
|
|
|
Size = Size2 = i = 0;
|
|
for( // search for specified SScope
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // init
|
|
; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( IS_STRING3_PRESENT(ThisAttrib) ) { // make space for sscope name
|
|
Size += sizeof(WCHAR)*(1+wcslen(ThisAttrib->String3));
|
|
}
|
|
i ++; // keep right count of # of subnets
|
|
}
|
|
|
|
Size += ROUND_UP_COUNT(sizeof(DHCP_SUPER_SCOPE_TABLE),ALIGN_WORST);
|
|
Size += ROUND_UP_COUNT(i*sizeof(DHCP_SUPER_SCOPE_TABLE_ENTRY), ALIGN_WORST);
|
|
|
|
Ptr = MemAlloc(Size); // allocate the blob
|
|
if( NULL == Ptr ) {
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
LocalTbl = (LPDHCP_SUPER_SCOPE_TABLE)Ptr;
|
|
Size = ROUND_UP_COUNT(sizeof(DHCP_SUPER_SCOPE_TABLE),ALIGN_WORST);
|
|
LocalTbl->cEntries = i;
|
|
if( i ) LocalTbl->pEntries = (LPDHCP_SUPER_SCOPE_TABLE_ENTRY)(Size+Ptr);
|
|
else LocalTbl->pEntries = NULL;
|
|
Size += ROUND_UP_COUNT(i*sizeof(DHCP_SUPER_SCOPE_TABLE_ENTRY), ALIGN_WORST);
|
|
|
|
i = 0;
|
|
for( // search for specified SScope
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // init
|
|
; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name
|
|
!IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
LocalTbl->pEntries[i].SubnetAddress = ThisAttrib->Address1;
|
|
LocalTbl->pEntries[i].SuperScopeNumber = 0;
|
|
LocalTbl->pEntries[i].NextInSuperScope = 0;
|
|
LocalTbl->pEntries[i].SuperScopeName = NULL;
|
|
|
|
if( !IS_STRING3_PRESENT(ThisAttrib) ) { // no sscope, nothin to do
|
|
i ++;
|
|
continue;
|
|
}
|
|
|
|
LocalTbl->pEntries[i].SuperScopeName = (LPWSTR)(Size + Ptr);
|
|
wcscpy((LPWSTR)(Size+Ptr), ThisAttrib->String3);
|
|
Size += sizeof(WCHAR)*(1+wcslen(ThisAttrib->String3));
|
|
i ++; // keep right count of # of subnets
|
|
}
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
|
|
nSubnets = i;
|
|
for( Index = 0; Index < nSubnets ; Index ++){ // calculate for each Index, next value
|
|
if( NULL == LocalTbl->pEntries[Index].SuperScopeName)
|
|
continue; // skip subnets that dont have sscope
|
|
|
|
LocalTbl->pEntries[Index].NextInSuperScope = Index;
|
|
|
|
for( i = 0; i < Index ; i ++ ) { // first set it to just prev subnet
|
|
if( NULL == LocalTbl->pEntries[i].SuperScopeName)
|
|
continue;
|
|
if( 0 == wcscmp(
|
|
LocalTbl->pEntries[Index].SuperScopeName,
|
|
LocalTbl->pEntries[i].SuperScopeName)
|
|
) { // both subnets have same superscope
|
|
LocalTbl->pEntries[Index].NextInSuperScope = i;
|
|
// set next as last match in array before position Index
|
|
}
|
|
}
|
|
|
|
for( i = Index + 1; i < nSubnets; i ++ ) {// check to see if any real next exists
|
|
if( NULL == LocalTbl->pEntries[i].SuperScopeName)
|
|
continue;
|
|
if( 0 == wcscmp(
|
|
LocalTbl->pEntries[Index].SuperScopeName,
|
|
LocalTbl->pEntries[i].SuperScopeName)
|
|
) { // both subnets have same superscope
|
|
LocalTbl->pEntries[Index].NextInSuperScope = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
*SScopeTbl = LocalTbl; // done.
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsServerAddSubnet tries to add a subnet to a given server. Each subnet
|
|
//DOC address has to be unique, but the other parameters dont have to.
|
|
//DOC The subnet address being added should not belong to any other subnet.
|
|
//DOC In this case it returns error ERROR_DDS_SUBNET_EXISTS
|
|
DWORD
|
|
DhcpDsServerAddSubnet( // create a new subnet
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN LPDHCP_SUBNET_INFO Info // info on new subnet to create
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, unused, i;
|
|
DWORD Index, nSubnets;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
EATTRIB Dummy;
|
|
LPWSTR SubnetObjName;
|
|
|
|
if( 0 != Reserved ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer || NULL == hServer->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == Info || NULL == ServerName )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( Info->SubnetAddress != (Info->SubnetAddress & Info->SubnetMask ) )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // fetch subnet array
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail
|
|
|
|
for( // search for specified SScope
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // init
|
|
; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( (Info->SubnetAddress & ThisAttrib->Address2 ) == ThisAttrib->Address1 ) {
|
|
return ERROR_DDS_SUBNET_EXISTS; // Info belongs to this subnet
|
|
}
|
|
|
|
if( Info->SubnetAddress == (ThisAttrib->Address1 & Info->SubnetMask) ) {
|
|
return ERROR_DDS_SUBNET_EXISTS; // Info subsumes some other subnet
|
|
}
|
|
}
|
|
|
|
SubnetObjName = MakeSubnetLocation(ServerName, Info->SubnetAddress);
|
|
if( NULL == SubnetObjName ) { // not enough memory?
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Err = CreateSubnetObject // try creating the subnet obj 1st
|
|
(
|
|
/* hDhcpC */ hDhcpC, // create obj here..
|
|
/* SubnetName */ SubnetObjName
|
|
);
|
|
if( ERROR_SUCCESS != Err ) { // could not create obj, dont proceed
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
MemFree(SubnetObjName);
|
|
return Err;
|
|
}
|
|
|
|
NothingPresent(&Dummy); // prepare info for new subnet
|
|
ADDRESS1_PRESENT(&Dummy); // subnet address
|
|
Dummy.Address1 = Info->SubnetAddress;
|
|
ADDRESS2_PRESENT(&Dummy); // subnet mask
|
|
Dummy.Address2 = Info->SubnetMask;
|
|
FLAGS1_PRESENT(&Dummy); // subnet state
|
|
Dummy.Flags1 = Info->SubnetState;
|
|
if( Info->SubnetName ) { // subnet name
|
|
STRING1_PRESENT(&Dummy);
|
|
Dummy.String1 = Info->SubnetName;
|
|
}
|
|
if( Info->SubnetComment ) { // subnet comment
|
|
STRING2_PRESENT(&Dummy);
|
|
Dummy.String2 = Info->SubnetComment;
|
|
}
|
|
ADSPATH_PRESENT(&Dummy); // subnet obj location
|
|
STOREGETTYPE_PRESENT(&Dummy);
|
|
Dummy.ADsPath = SubnetObjName;
|
|
Dummy.StoreGetType = StoreGetChildType;
|
|
|
|
Err = MemArrayAddElement(&Subnets, &Dummy); // add new attrib at end
|
|
|
|
if( ERROR_SUCCESS != Err ) { // add failed for some reason
|
|
MemFree(SubnetObjName);
|
|
MemArrayFree(&Subnets, MemFreeFunc); // cleanup any mem used
|
|
return Err;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // write back new info onto DS
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescripti.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescriptio.. */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
MemFree(SubnetObjName);
|
|
Err2 = MemArrayLastLoc(&Subnets, &Loc); //= require ERROR_SUCCESS == Err
|
|
Err2 = MemArrayDelElement(&Subnets, &Loc, &ThisAttrib);
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsServerDelSubnet removes a subnet from a given server. It removes not
|
|
//DOC just the subnet, but also all dependent objects like reservations etc.
|
|
//DOC This fn returns ERROR_DDS_SUBNET_NOT_PRESENT if the subnet is not found.
|
|
DWORD
|
|
DhcpDsServerDelSubnet( // Delete the subnet
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create obj
|
|
IN LPSTORE_HANDLE hServer, // server obj
|
|
IN DWORD Reserved, // for future use, must be zero
|
|
IN LPWSTR ServerName, // name of dhcp server 2 del off
|
|
IN DWORD IpAddress // ip address of subnet to del
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
BOOL fSubnetExists;
|
|
BOOL fSubnetDeleted;
|
|
LPWSTR SubnetCNName;
|
|
LPWSTR SubnetLoc;
|
|
DWORD SubnetLocType;
|
|
|
|
if( NULL == hServer || NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of subnets
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets, // array of PEATTRIB 's
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
fSubnetExists = fSubnetDeleted = FALSE;
|
|
for( // search list of subnets
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next element
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ThisAttrib->Address1 == IpAddress ) { // matching address?
|
|
fSubnetExists = TRUE;
|
|
Err2 = MemArrayDelElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= ERROR_SUCCESS == Err2 && NULL != ThisAttrib
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !fSubnetExists ) { // no matching subnet found
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_DDS_SUBNET_NOT_PRESENT;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // now set the new attrib list
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
MemArrayFree(&Subnets, MemFreeFunc); // free allocated memory
|
|
if( ERROR_SUCCESS != Err) { // check err for DhcpDsSetLists
|
|
MemFree(ThisAttrib);
|
|
return Err;
|
|
}
|
|
|
|
if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // remember the location to delete
|
|
SubnetLocType = ThisAttrib->StoreGetType;
|
|
SubnetLoc = ThisAttrib->ADsPath;
|
|
} else {
|
|
SubnetLoc = NULL;
|
|
}
|
|
|
|
if( NULL == SubnetLoc ) { // Dont know location
|
|
SubnetCNName = MakeSubnetLocation(ServerName,IpAddress);
|
|
SubnetLoc = SubnetCNName; // set name for subnet obj
|
|
SubnetLocType = StoreGetChildType; // assume located in DhcpC container
|
|
} else {
|
|
SubnetCNName = NULL; // Did not allocate subnet name
|
|
}
|
|
|
|
if( NULL == SubnetLoc ) { // MakeSubnetLocation failed
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else { // lets try to delete the subnet
|
|
Err = ServerDeleteSubnet // delete the dhcp subnet object
|
|
(
|
|
/* hDhcpC */ hDhcpC,
|
|
/* ServerName */ ServerName,
|
|
/* hServer */ hServer,
|
|
/* ADsPath */ SubnetLoc,
|
|
/* StoreGetType */ SubnetLocType
|
|
);
|
|
}
|
|
|
|
if( SubnetCNName ) MemFree(SubnetCNName); // if we allocated mem, free it
|
|
MemFree(ThisAttrib); // lonely attrib needs to be freed
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsServerModifySubnet changes the subnet name, comment, state, mask
|
|
//DOC fields of the subnet. Actually, currently, the mask should probably not
|
|
//DOC be changed, as no checks are performed in this case. The address cannot
|
|
//DOC be changed.. If the subnet is not present, the error returned is
|
|
//DOC ERROR_DDS_SUBNET_NOT_PRESENT
|
|
DWORD
|
|
DhcpDsServerModifySubnet( // modify subnet info
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN LPDHCP_SUBNET_INFO Info // info on new subnet to create
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
BOOL fSubnetExists, fSubnetDeleted;
|
|
|
|
if( NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == Info )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of subnets
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets, // array of PEATTRIB 's
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
fSubnetExists = fSubnetDeleted = FALSE;
|
|
for( // search list of subnets
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // initialize
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next element
|
|
) {
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ThisAttrib->Address1 == Info->SubnetAddress ) {
|
|
fSubnetExists = TRUE; // matching address?
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !fSubnetExists ) { // no matching subnet found
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_DDS_SUBNET_NOT_PRESENT;
|
|
}
|
|
|
|
ThisAttrib->Address2 = Info->SubnetMask; // alter information
|
|
FLAGS1_PRESENT(ThisAttrib);
|
|
ThisAttrib->Flags1 = Info->SubnetState;
|
|
if( NULL == Info->SubnetName ) {
|
|
STRING1_ABSENT(ThisAttrib);
|
|
} else {
|
|
STRING1_PRESENT(ThisAttrib);
|
|
ThisAttrib->String1 = Info->SubnetName;
|
|
}
|
|
if( NULL == Info->SubnetComment ) {
|
|
STRING2_ABSENT(ThisAttrib);
|
|
} else {
|
|
STRING2_PRESENT(ThisAttrib);
|
|
ThisAttrib->String2 = Info->SubnetComment;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // now set the new attrib list
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
MemArrayFree(&Subnets, MemFreeFunc); // free allocated memory
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsServerEnumSubnets is not yet implemented.
|
|
DWORD
|
|
DhcpDsServerEnumSubnets( // get subnet list
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
OUT LPDHCP_IP_ARRAY *SubnetsArray // give array of subnets
|
|
) //EndExport(function)
|
|
{
|
|
LPDHCP_IP_ARRAY LocalSubnetArray;
|
|
DWORD Err, Err2, unused, Size;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
|
|
if( NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == SubnetsArray )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of subnets
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets, // array of PEATTRIB 's
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
LocalSubnetArray = MemAlloc(sizeof(DHCP_IP_ARRAY));
|
|
if( NULL == LocalSubnetArray ) {
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
LocalSubnetArray->NumElements = 0;
|
|
LocalSubnetArray->Elements = NULL;
|
|
Size = sizeof(DHCP_IP_ADDRESS)*MemArraySize(&Subnets);
|
|
if( Size ) LocalSubnetArray->Elements = MemAlloc(Size);
|
|
|
|
for( // accumulate the subnets
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // for each subnet
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until there are no more
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next
|
|
) {
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
LocalSubnetArray->Elements[LocalSubnetArray->NumElements++] = ThisAttrib->Address1;
|
|
}
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
*SubnetsArray = LocalSubnetArray;
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsServerGetSubnetInfo is not yet implemented.
|
|
DWORD
|
|
DhcpDsServerGetSubnetInfo( // get info on subnet
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DHCP_IP_ADDRESS SubnetAddress, // address of subnet to get info for
|
|
OUT LPDHCP_SUBNET_INFO *SubnetInfo // o/p: allocated info
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, unused;
|
|
ARRAY Subnets;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
LPDHCP_SUBNET_INFO Info;
|
|
BOOL fSubnetExists;
|
|
|
|
if( NULL == hDhcpC ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == SubnetInfo )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of subnets
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hServer,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ &Subnets, // array of PEATTRIB 's
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
fSubnetExists = FALSE;
|
|
for( // accumulate the subnets
|
|
Err = MemArrayInitLoc(&Subnets, &Loc) // for each subnet
|
|
; ERROR_FILE_NOT_FOUND != Err ; // until there are no more
|
|
Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next
|
|
) {
|
|
Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib);
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ThisAttrib->Address1 == SubnetAddress ) {
|
|
fSubnetExists = TRUE; // found the required subnet
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !fSubnetExists ) { // no subnet matching address
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_DDS_SUBNET_NOT_PRESENT;
|
|
}
|
|
|
|
Info = MemAlloc(sizeof(LPDHCP_SUBNET_INFO));
|
|
if( NULL == Info) {
|
|
MemArrayFree(&Subnets, MemFreeFunc);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Info->SubnetAddress = ThisAttrib->Address1; // subnet address
|
|
Info->SubnetMask = ThisAttrib->Address2; // subnet mask
|
|
|
|
if( !IS_STRING1_PRESENT(ThisAttrib) ) { // subnet name?
|
|
Info->SubnetName = NULL;
|
|
} else {
|
|
Info->SubnetName = MemAlloc(sizeof(WCHAR) * (1+wcslen(ThisAttrib->String1)));
|
|
if( NULL != Info->SubnetName ) {
|
|
wcscpy(Info->SubnetName, ThisAttrib->String1);
|
|
}
|
|
}
|
|
|
|
if( !IS_STRING2_PRESENT(ThisAttrib) ) { // subnet comment?
|
|
Info->SubnetComment = NULL; // no subnet comment
|
|
} else {
|
|
Info->SubnetComment = MemAlloc(sizeof(WCHAR) * (1+wcslen(ThisAttrib->String2)));
|
|
if( NULL != Info->SubnetComment ) {
|
|
wcscpy(Info->SubnetComment, ThisAttrib->String2);
|
|
}
|
|
}
|
|
|
|
if( !IS_FLAGS1_PRESENT(ThisAttrib) ) { // subnet state information
|
|
Info->SubnetState = DhcpSubnetEnabled;
|
|
} else {
|
|
Info->SubnetState = ThisAttrib->Flags1;
|
|
}
|
|
|
|
MemArrayFree(&Subnets, MemFreeFunc); // clear up memory
|
|
*SubnetInfo = Info;
|
|
|
|
Info->PrimaryHost.IpAddress = 0; // : unsupported fields..
|
|
Info->PrimaryHost.NetBiosName = NULL;
|
|
Info->PrimaryHost.HostName = NULL;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsSubnetAddRangeOrExcl adds a range/excl to an existing subnet.
|
|
//DOC If there is a collision with between ranges, then the error code returned
|
|
//DOC is ERROR_DDS_POSSIBLE_RANGE_CONFLICT. Note that no checks are made for
|
|
//DOC exclusions though. Also, if a RANGE is extended via this routine, then
|
|
//DOC there is no error returned, but a limitation currently is that multiple
|
|
//DOC ranges (two only right) cannot be simultaneously extended.
|
|
//DOC BUBGUG: The basic check of whether the range belongs in the subnet is
|
|
//DOC not done..
|
|
DWORD
|
|
DhcpDsSubnetAddRangeOrExcl( // add a range or exclusion
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DWORD Start, // start addr in range
|
|
IN DWORD End, // end addr in range
|
|
IN BOOL RangeOrExcl // TRUE ==> Range,FALSE ==> Excl
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, unused;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
EATTRIB Dummy;
|
|
ARRAY Ranges;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hSubnet || NULL == hSubnet->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( Start > End ) return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ &Ranges, // array of PEATTRIB 's
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL);
|
|
ThisAttrib = NULL;
|
|
if( FindCollisions(&Ranges,Start,End,Type, &ThisAttrib) ) {
|
|
MemArrayFree(&Ranges, MemFreeFunc);
|
|
return ERROR_DDS_POSSIBLE_RANGE_CONFLICT; // hit a range conflict!
|
|
}
|
|
|
|
if( NULL != ThisAttrib ) { // this is a collision case
|
|
if( Start == ThisAttrib->Address2 ) { // this is the collapse point
|
|
ThisAttrib->Address2 = End;
|
|
} else {
|
|
ThisAttrib->Address1 = Start;
|
|
}
|
|
} else { // not a collision
|
|
NothingPresent(&Dummy); // create a new range
|
|
ADDRESS1_PRESENT(&Dummy); // range start
|
|
Dummy.Address1 = Start;
|
|
ADDRESS2_PRESENT(&Dummy); // range end
|
|
Dummy.Address2 = End;
|
|
FLAGS1_PRESENT(&Dummy);
|
|
Dummy.Flags1 = 0;
|
|
FLAGS2_PRESENT(&Dummy); // range type or excl type?
|
|
Dummy.Flags2 = Type;
|
|
|
|
Err = MemArrayAddElement(&Ranges, &Dummy);
|
|
if( ERROR_SUCCESS != Err ) { // could not create new lists
|
|
MemArrayFree(&Ranges, MemFreeFunc);
|
|
return Err;
|
|
}
|
|
}
|
|
|
|
Err = DhcpDsSetLists // write back new list to ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ &Ranges,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
if( NULL == ThisAttrib ) { // in case we added the new range
|
|
Err2 = MemArrayLastLoc(&Ranges, &Loc); // try to delete frm mem the new elt
|
|
Err2 = MemArrayDelElement(&Ranges, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && ThisAttrib == &Dummy
|
|
}
|
|
|
|
MemArrayFree(&Ranges, MemFreeFunc);
|
|
return Err; // DhcpDsSetLists's ret code
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsSubnetDelRangeOrExcl deletes a range or exclusion from off the ds.
|
|
//DOC To specify range, set the RangeOrExcl parameter to TRUE.
|
|
DWORD
|
|
DhcpDsSubnetDelRangeOrExcl( // del a range or exclusion
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DWORD Start, // start addr in range
|
|
IN DWORD End, // end addr in range
|
|
IN BOOL RangeOrExcl // TRUE ==> Range,FALSE ==> Excl
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, ThisType, unused;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
ARRAY Ranges;
|
|
BOOL Changed;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hSubnet || NULL == hSubnet->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( Start > End ) return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ &Ranges, // array of PEATTRIB 's
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL);
|
|
Changed = FALSE;
|
|
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(&Ranges, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(&Ranges, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(&Ranges, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE
|
|
ThisType = RANGE_TYPE_RANGE;
|
|
} else ThisType = ThisAttrib->Flags2;
|
|
|
|
if( Start != ThisAttrib->Address1 ||
|
|
End != ThisAttrib->Address2 ) { // range mismatch
|
|
continue;
|
|
}
|
|
|
|
if(Type != ThisType ) { // looking for x, bug this is !x.
|
|
continue;
|
|
}
|
|
|
|
Err2 = MemArrayDelElement(&Ranges, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
MemFreeFunc(ThisAttrib);
|
|
Changed = TRUE;
|
|
}
|
|
|
|
if( !Changed ) { // nothing found ni registry
|
|
Err = ERROR_DDS_RANGE_DOES_NOT_EXIST;
|
|
} else {
|
|
Err = DhcpDsSetLists // write back new list to ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ &Ranges,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
}
|
|
|
|
MemArrayFree(&Ranges, MemFreeFunc);
|
|
return Err; // DhcpDsSetLists's ret code
|
|
}
|
|
|
|
DWORD
|
|
ConvertAttribToRanges( // convert from array of attribs ..
|
|
IN DWORD nRanges, // # of ranges,
|
|
IN PARRAY Ranges, // input array of attribs
|
|
IN ULONG Type, // TYPE_RANGE_TYPE or TYPE_EXCLUSION_TYPE?
|
|
OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pRanges //output array..
|
|
)
|
|
{
|
|
DWORD Err;
|
|
ULONG Count, ThisType;
|
|
PEATTRIB ThisAttrib;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 localRanges;
|
|
ARRAY_LOCATION Loc;
|
|
DHCP_IP_RANGE *ThisRange;
|
|
|
|
localRanges = MemAlloc(sizeof(DHCP_SUBNET_ELEMENT_INFO_ARRAY_V4));
|
|
*pRanges = localRanges;
|
|
if( NULL == localRanges ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
if( 0 == nRanges ) {
|
|
localRanges->NumElements = 0;
|
|
localRanges->Elements = NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
localRanges->Elements = MemAlloc(nRanges*sizeof(DHCP_SUBNET_ELEMENT_DATA_V4));
|
|
if( NULL == localRanges->Elements ) {
|
|
MemFree(localRanges);
|
|
*pRanges = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
localRanges->NumElements = nRanges;
|
|
for( Count = 0 ; Count < nRanges ; Count ++ ) {
|
|
localRanges->Elements[Count].Element.IpRange =
|
|
localRanges->Elements[Count].Element.ExcludeIpRange =
|
|
ThisRange = MemAlloc(sizeof(DHCP_IP_RANGE));
|
|
if( NULL == ThisRange ) { // oops could not allocate ? free everything and bail!
|
|
while( Count != 0 ) { // remember Count is unsigned ..
|
|
Count --;
|
|
MemFree(localRanges->Elements[Count].Element.IpRange);
|
|
}
|
|
MemFree(localRanges->Elements);
|
|
MemFree(localRanges);
|
|
*pRanges = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
Count = 0;
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(Ranges, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(Ranges, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(Ranges, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE
|
|
ThisType = RANGE_TYPE_RANGE;
|
|
} else ThisType = ThisAttrib->Flags2;
|
|
|
|
if(Type != ThisType ) { // looking for x, bug this is !x.
|
|
continue;
|
|
}
|
|
|
|
//= require ThisAttrib->Address1 < ThisAttrib->Address2
|
|
|
|
if( RANGE_TYPE_RANGE == Type ) {
|
|
localRanges->Elements[Count].ElementType = DhcpIpRanges ;
|
|
localRanges->Elements[Count].Element.IpRange->StartAddress = ThisAttrib->Address1;
|
|
localRanges->Elements[Count].Element.IpRange->EndAddress = ThisAttrib->Address2;
|
|
} else {
|
|
localRanges->Elements[Count].ElementType = DhcpExcludedIpRanges;
|
|
localRanges->Elements[Count].Element.ExcludeIpRange->StartAddress = ThisAttrib->Address1;
|
|
localRanges->Elements[Count].Element.ExcludeIpRange->EndAddress = ThisAttrib->Address2;
|
|
}
|
|
|
|
Count ++;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsEnumRangesOrExcl is not yet implemented.
|
|
DWORD
|
|
DhcpDsEnumRangesOrExcl( // enum list of ranges 'n excl
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN BOOL RangeOrExcl, // TRUE ==> Range, FALSE ==> Excl
|
|
OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pRanges
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, ThisType, unused;
|
|
DWORD Count;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
ARRAY Ranges;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hSubnet || NULL == hSubnet->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ &Ranges, // array of PEATTRIB 's
|
|
/* Sites */ NULL,
|
|
/* Reservations */ NULL,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL);
|
|
|
|
Count = 0;
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(&Ranges, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(&Ranges, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(&Ranges, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address
|
|
!IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE
|
|
ThisType = RANGE_TYPE_RANGE;
|
|
} else ThisType = ThisAttrib->Flags2;
|
|
|
|
if(Type != ThisType ) { // looking for x, bug this is !x.
|
|
continue;
|
|
}
|
|
|
|
Count ++;
|
|
}
|
|
|
|
Err = ConvertAttribToRanges(Count, &Ranges, Type, pRanges);
|
|
MemArrayFree(&Ranges, MemFreeFunc);
|
|
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsSubnetAddReservation tries to add a reservation object in the DS.
|
|
//DOC Neither the ip address not hte hw-address must exist in the DS prior to this.
|
|
//DOC If they do exist, the error returned is ERROR_DDS_RESERVATION_CONFLICT.
|
|
//DOC No checks are made on the sanity of the address in this subnet..
|
|
DWORD
|
|
DhcpDsSubnetAddReservation( // add a reservation
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DWORD ReservedAddr, // reservation ip address to add
|
|
IN LPBYTE HwAddr, // RAW [ethernet?] hw addr of the client
|
|
IN DWORD HwAddrLen, // length in # of bytes of hw addr
|
|
IN DWORD ClientType // client is BOOTP, DHCP, or both?
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, ClientUIDSize, unused;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
EATTRIB Dummy;
|
|
ARRAY Reservations;
|
|
LPBYTE ClientUID;
|
|
LPWSTR ReservationCNName;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == HwAddr || 0 == HwAddrLen )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
ClientUID = NULL;
|
|
Err = DhcpMakeClientUID(
|
|
HwAddr,
|
|
HwAddrLen,
|
|
HARDWARE_TYPE_10MB_EITHERNET,
|
|
ReservedAddr,
|
|
&ClientUID,
|
|
&ClientUIDSize
|
|
);
|
|
if( ERROR_SUCCESS != Err ) { // should not happen
|
|
return Err;
|
|
}
|
|
|
|
Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ &Reservations,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) {
|
|
MemFree(ClientUID);
|
|
return Err;
|
|
}
|
|
|
|
for( // search for existing reservation
|
|
Err = MemArrayInitLoc(&Reservations, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(&Reservations, &Loc)
|
|
) {
|
|
BOOL Mismatch;
|
|
|
|
//= require ERROR_SUCCESS == Err
|
|
Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) // no address for reservations
|
|
|| !IS_BINARY1_PRESENT(ThisAttrib) // no hw len specified
|
|
|| !IS_FLAGS1_PRESENT(ThisAttrib) ) { // no client type present
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
Mismatch = FALSE;
|
|
if( ThisAttrib->Address1 == ReservedAddr ) {
|
|
Mismatch = TRUE; // address already reserved
|
|
}
|
|
|
|
if( ThisAttrib->BinLen1 == ClientUIDSize // see if hw address matches
|
|
&& 0 == memcmp(ThisAttrib->Binary1, ClientUID, ClientUIDSize)
|
|
) {
|
|
Mismatch = TRUE;
|
|
}
|
|
|
|
if( Mismatch ) { // ip addr or hw-addr in use
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
MemFree(ClientUID);
|
|
return ERROR_DDS_RESERVATION_CONFLICT;
|
|
}
|
|
}
|
|
|
|
ReservationCNName = MakeReservationLocation(ServerName, ReservedAddr);
|
|
if( NULL == ReservationCNName ) { // not enough mem to create string
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
Err = CreateReservationObject // create the new reservation object
|
|
(
|
|
/* hDhcpC */ hDhcpC, // container to create obj in
|
|
/* ReserveCNName */ ReservationCNName
|
|
);
|
|
}
|
|
if( ERROR_SUCCESS != Err ) { // could not create reservation object
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
MemFree(ClientUID);
|
|
return Err;
|
|
}
|
|
|
|
NothingPresent(&Dummy); // create a new reservation
|
|
ADDRESS1_PRESENT(&Dummy); // ip address
|
|
Dummy.Address1 = ReservedAddr;
|
|
FLAGS1_PRESENT(&Dummy); // client type
|
|
Dummy.Flags1 = ClientType;
|
|
BINARY1_PRESENT(&Dummy); // client uid
|
|
Dummy.BinLen1 = ClientUIDSize;
|
|
Dummy.Binary1 = ClientUID;
|
|
STOREGETTYPE_PRESENT(&Dummy); // relative location for reservation obj
|
|
ADSPATH_PRESENT(&Dummy);
|
|
Dummy.StoreGetType = StoreGetChildType;
|
|
Dummy.ADsPath = ReservationCNName;
|
|
|
|
Err = MemArrayAddElement(&Reservations,&Dummy);
|
|
if( ERROR_SUCCESS != Err ) { // oops, cannot add reservation
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
MemFree(ClientUID);
|
|
MemFree(ReservationCNName);
|
|
return Err;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // write back new list to ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ &Reservations,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
|
|
Err2 = MemArrayLastLoc(&Reservations, &Loc); // try to delete frm mem the new elt
|
|
Err2 = MemArrayDelElement(&Reservations, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && ThisAttrib == &Dummy
|
|
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
MemFree(ClientUID);
|
|
MemFree(ReservationCNName);
|
|
return Err; // DhcpDsSetLists's ret code
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsSubnetDelReservation deletes a reservation from the DS.
|
|
//DOC If the reservation does not exist, it returns ERROR_DDS_RESERVATION_NOT_PRESENT.
|
|
//DOC Reservations cannot be deleted by anything but ip address for now.
|
|
DWORD
|
|
DhcpDsSubnetDelReservation( // delete a reservation
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DWORD ReservedAddr // ip address to delete reserv. by
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, ThisType, unused;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
ARRAY Reservations;
|
|
BOOL ReservationExists;
|
|
LPWSTR ReservationLocPath, ReservationCNName;
|
|
DWORD ReservationLocType;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ &Reservations,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
ReservationExists = FALSE;
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(&Reservations, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(&Reservations, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address
|
|
!IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
if( ThisAttrib->Address1 != ReservedAddr ) {
|
|
continue; // not this reservation
|
|
}
|
|
|
|
ReservationExists = TRUE;
|
|
Err2 = MemArrayDelElement(&Reservations, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
break;
|
|
}
|
|
|
|
if( !ReservationExists ) { // no matching reservation found
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
return ERROR_DDS_RESERVATION_NOT_PRESENT;
|
|
}
|
|
|
|
Err = DhcpDsSetLists // write back new list to ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* SetParams */ &unused,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ &Reservations,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription.. */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* ClassDescription */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
if( ERROR_SUCCESS != Err ) {
|
|
MemFree(ThisAttrib);
|
|
return Err;
|
|
}
|
|
|
|
if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // deleted reservation's location in ds
|
|
ReservationLocType = ThisAttrib->StoreGetType;
|
|
ReservationLocPath = ThisAttrib->ADsPath;
|
|
} else {
|
|
ReservationLocPath = NULL;
|
|
}
|
|
|
|
if( NULL == ReservationLocPath ) { // no path present, but guess it anyways
|
|
ReservationCNName = MakeReservationLocation(ServerName,ReservedAddr);
|
|
ReservationLocPath = ReservationCNName; // same name that is used generally
|
|
ReservationLocType = StoreGetChildType; // child object
|
|
} else {
|
|
ReservationCNName = NULL; // NULL indicating no alloc
|
|
}
|
|
|
|
if( NULL == ReservationLocPath ) { // dont know what to delete..
|
|
Err = ERROR_NOT_ENOUGH_MEMORY; // MakeReservationLocation failed
|
|
} else { // try to delete subnet object
|
|
Err = SubnetDeleteReservation // actual delete in ds
|
|
(
|
|
/* hDhcpC */ hDhcpC,
|
|
/* ServerName */ ServerName,
|
|
/* hServer */ hServer,
|
|
/* hSubnet */ hSubnet,
|
|
/* ADsPath */ ReservationLocPath,
|
|
/* StoreGetType */ ReservationLocType
|
|
);
|
|
}
|
|
|
|
if( ReservationCNName ) MemFree(ReservationCNName);
|
|
MemFree(ThisAttrib); // free all ptrs left..
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
LPBYTE _inline
|
|
DupeBytes( // allocate mem and copy bytes
|
|
IN LPBYTE Data,
|
|
IN ULONG DataLen
|
|
)
|
|
{
|
|
LPBYTE NewData;
|
|
|
|
if( 0 == DataLen ) return NULL;
|
|
NewData = MemAlloc(DataLen);
|
|
if( NULL != NewData ) {
|
|
memcpy(NewData, Data, DataLen);
|
|
}
|
|
return NewData;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ConvertAttribToReservations( // convert from arry of attribs ..
|
|
IN DWORD nRes, // # of reservatiosn to convert
|
|
IN PARRAY Res, // the actual array of reservations
|
|
OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pResInfo
|
|
)
|
|
{
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 localRes;
|
|
DWORD Err, Count;
|
|
LPWSTR ReservationLocPath, ReservationCNName;
|
|
DWORD ReservationLocType;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
ARRAY Reservations;
|
|
LPDHCP_IP_RESERVATION_V4 ThisRes;
|
|
LPVOID Data;
|
|
|
|
localRes = MemAlloc(sizeof(DHCP_SUBNET_ELEMENT_INFO_ARRAY_V4));
|
|
*pResInfo = localRes;
|
|
if( NULL == localRes ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
if( 0 == nRes ) {
|
|
localRes->NumElements = 0;
|
|
localRes->Elements = NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
localRes->Elements = MemAlloc(nRes*sizeof(DHCP_SUBNET_ELEMENT_DATA_V4));
|
|
if( NULL == localRes->Elements ) {
|
|
MemFree(localRes);
|
|
*pResInfo = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
localRes->NumElements = nRes;
|
|
for( Count = 0 ; Count < nRes ; Count ++ ) {
|
|
localRes->Elements[Count].Element.ReservedIp =
|
|
ThisRes = MemAlloc(sizeof(DHCP_IP_RESERVATION_V4));
|
|
if( NULL != ThisRes ) { // successfull allocation..
|
|
ThisRes->ReservedForClient = MemAlloc(sizeof(DHCP_CLIENT_UID));
|
|
if( NULL == ThisRes->ReservedForClient) {
|
|
MemFree(ThisRes); // duh it failed here..
|
|
ThisRes = NULL; // fake an upper level fail
|
|
}
|
|
}
|
|
|
|
if( NULL == ThisRes ) { // oops could not allocate ? free everything and bail!
|
|
while( Count != 0 ) { // remember Count is unsigned ..
|
|
Count --;
|
|
MemFree(localRes->Elements[Count].Element.ReservedIp->ReservedForClient);
|
|
MemFree(localRes->Elements[Count].Element.ReservedIp);
|
|
}
|
|
MemFree(localRes->Elements);
|
|
MemFree(localRes);
|
|
*pResInfo = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
Count = 0;
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(Res, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(Res, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(Res, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address
|
|
!IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
localRes->Elements[Count].ElementType = DhcpReservedIps;
|
|
if( IS_FLAGS1_PRESENT(ThisAttrib) ) {
|
|
localRes->Elements[Count].Element.ReservedIp->bAllowedClientTypes = (BYTE)ThisAttrib->Flags1;
|
|
} else {
|
|
localRes->Elements[Count].Element.ReservedIp->bAllowedClientTypes = 0;
|
|
}
|
|
|
|
localRes->Elements[Count].Element.ReservedIp->ReservedIpAddress = ThisAttrib->Address1;
|
|
localRes->Elements[Count].Element.ReservedIp->ReservedForClient->Data =
|
|
Data = DupeBytes(ThisAttrib->Binary1, ThisAttrib->BinLen1);
|
|
if( NULL == Data ) { // could not allocate memory..
|
|
localRes->Elements[Count].Element.ReservedIp->ReservedForClient->DataLength = 0;
|
|
} else {
|
|
localRes->Elements[Count].Element.ReservedIp->ReservedForClient->DataLength = ThisAttrib->BinLen1;
|
|
}
|
|
|
|
Count++;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsEnumReservations enumerates the reservations..
|
|
DWORD
|
|
DhcpDsEnumReservations( // enumerate reservations frm DS
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pReservations
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err, Err2, Type, ThisType, unused;
|
|
DWORD Count;
|
|
ARRAY_LOCATION Loc;
|
|
PEATTRIB ThisAttrib;
|
|
ARRAY Reservations;
|
|
|
|
if( NULL == hDhcpC || NULL == hServer ) // check params
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle )
|
|
return ERROR_INVALID_PARAMETER;
|
|
if( NULL == ServerName || 0 != Reserved )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err
|
|
Err = DhcpDsGetLists // get list of ranges frm ds
|
|
(
|
|
/* Reserved */ DDS_RESERVED_DWORD,
|
|
/* hStore */ hSubnet,
|
|
/* RecursionDepth */ 0xFFFFFFFF,
|
|
/* Servers */ NULL,
|
|
/* Subnets */ NULL,
|
|
/* IpAddress */ NULL,
|
|
/* Mask */ NULL,
|
|
/* Ranges */ NULL,
|
|
/* Sites */ NULL,
|
|
/* Reservations */ &Reservations,
|
|
/* SuperScopes */ NULL,
|
|
/* OptionDescription */ NULL,
|
|
/* OptionsLocation */ NULL,
|
|
/* Options */ NULL,
|
|
/* Classes */ NULL
|
|
);
|
|
if( ERROR_SUCCESS != Err ) return Err;
|
|
|
|
Count = 0;
|
|
for( // look for matching range/excl
|
|
Err = MemArrayInitLoc(&Reservations, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Err ;
|
|
Err = MemArrayNextLoc(&Reservations, &Loc)
|
|
) {
|
|
Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib);
|
|
//= require ERROR_SUCCESS == Err && NULL != ThisAttrib
|
|
|
|
if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address
|
|
!IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified
|
|
continue; //= ds inconsistent
|
|
}
|
|
|
|
}
|
|
|
|
Err = ConvertAttribToReservations(Count, &Reservations, pReservations);
|
|
|
|
MemArrayFree(&Reservations, MemFreeFunc);
|
|
return Err;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
//DOC DhcpDsEnumSubnetElements enumerates the list of subnet elements in a
|
|
//DOC subnet... such as IpRanges, Exclusions, Reservations..
|
|
//DOC
|
|
DWORD
|
|
DhcpDsEnumSubnetElements(
|
|
IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects
|
|
IN OUT LPSTORE_HANDLE hServer, // server object
|
|
IN OUT LPSTORE_HANDLE hSubnet, // subnet object
|
|
IN DWORD Reserved, // for future use, reserved
|
|
IN LPWSTR ServerName, // name of server we're using
|
|
IN DHCP_SUBNET_ELEMENT_TYPE ElementType, // what kind of elt to enum?
|
|
OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *ElementInfo
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Err;
|
|
|
|
switch(ElementType) {
|
|
case DhcpIpRanges:
|
|
Err = DhcpDsEnumRangesOrExcl(
|
|
hDhcpC,
|
|
hServer,
|
|
hSubnet,
|
|
Reserved,
|
|
ServerName,
|
|
TRUE,
|
|
ElementInfo
|
|
);
|
|
break;
|
|
case DhcpExcludedIpRanges:
|
|
Err = DhcpDsEnumRangesOrExcl(
|
|
hDhcpC,
|
|
hServer,
|
|
hSubnet,
|
|
Reserved,
|
|
ServerName,
|
|
FALSE,
|
|
ElementInfo
|
|
);
|
|
break;
|
|
case DhcpReservedIps:
|
|
Err = DhcpDsEnumReservations(
|
|
hDhcpC,
|
|
hServer,
|
|
hSubnet,
|
|
Reserved,
|
|
ServerName,
|
|
ElementInfo
|
|
);
|
|
break;
|
|
default:
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
return Err;
|
|
}
|
|
|
|
//================================================================================
|
|
// end of file
|
|
//================================================================================
|