You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1086 lines
38 KiB
1086 lines
38 KiB
//================================================================================
|
|
// 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;
|
|
|
|
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)(<operator>(dhcpServer="i<ip>$*")(dhcpServer="*s<hostname>*")))
|
|
//
|
|
|
|
LPWSTR
|
|
MakeFilter(
|
|
LPWSTR LookupServerIP, // Printable IP addr
|
|
LPWSTR HostName,
|
|
LDAP_OPERATOR_ENUM Operator
|
|
)
|
|
{
|
|
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 {
|
|
|
|
// Make large enough buffer
|
|
Len = wcslen( HostName ) + wcslen( LookupServerIP ) + 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 - 1, 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 - 1, L"*s%ws$*", HostName );
|
|
Require( CopiedLen > 0 );
|
|
Filter3 = MakeLdapFilter( DHCP_ATTRIB_SERVERS,
|
|
LDAP_OPERATOR_EQUAL_TO, Buf, TRUE );
|
|
|
|
if ( NULL == Filter3 ) {
|
|
break;
|
|
}
|
|
|
|
// make (<operator>(<ipfilter>)(<hostfilter))
|
|
Filter4 = MakeLdapFilter( Filter2, Operator,
|
|
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 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;
|
|
}
|
|
|
|
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;
|
|
} // GetListOfAllServersMatchingFilter()
|
|
|
|
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 ServerLocation,// Container where this will go in
|
|
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;
|
|
|
|
if ( NULL == ServerLocation ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
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 for this object
|
|
(
|
|
/* 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;
|
|
|
|
#ifdef DBG
|
|
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.
|
|
//
|
|
|
|
Require( fExactMatch == FALSE );
|
|
}
|
|
} // for
|
|
|
|
#endif
|
|
|
|
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 = StoreGetChildType;
|
|
}
|
|
|
|
Err = MemArrayAddElement(&Servers, &DummyAttrib);
|
|
if( ERROR_SUCCESS != Err ) { // could not add this to attrib array
|
|
MemArrayFree(&Servers, MemFreeFunc); // free allocated memory
|
|
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
|
|
|
|
return Err;
|
|
} // DhcpDsAddServerInternal()
|
|
|
|
//================================================================================
|
|
// 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;
|
|
ARRAY Servers;
|
|
ARRAY_LOCATION Loc;
|
|
LPWSTR ServerLocation;
|
|
DWORD ServerLocType;
|
|
STORE_HANDLE hDhcpServer;
|
|
LPWSTR SearchFilter;
|
|
WCHAR PrintableIp[ 20 ];
|
|
LPWSTR SName;
|
|
|
|
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;
|
|
|
|
ServerLocation = NULL;
|
|
|
|
do {
|
|
Err = MemArrayInit( &Servers ); // cant fail
|
|
//= require ERROR_SUCCESS == Err
|
|
|
|
DsAuthPrint(( L"DhcpAddServer() \n" ));
|
|
|
|
// Make a printable IP
|
|
ConvertAddressToLPWSTR( IpAddress, PrintableIp );
|
|
|
|
DsAuthPrint(( L"DhcpAddServer() : PrintableIp = %ws\n", PrintableIp ));
|
|
|
|
SearchFilter = MakeFilter( PrintableIp, ServerName, LDAP_OPERATOR_AND );
|
|
if ( NULL == SearchFilter ) {
|
|
Err = ERROR_INVALID_PARAMETER; // get a better error code
|
|
break;
|
|
}
|
|
|
|
DsAuthPrint(( L"DhcpDsAddServer() : Filter = %ws\n", SearchFilter ));
|
|
|
|
Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers,
|
|
SearchFilter );
|
|
MemFree( SearchFilter );
|
|
if( ERROR_SUCCESS != Err ) {
|
|
break;
|
|
}
|
|
|
|
// There should only be one entry matching <hostname> and <ip>
|
|
// if the entry already exists
|
|
|
|
Require( MemArraySize( &Servers ) <= 1);
|
|
|
|
if ( MemArraySize( &Servers ) > 0 ) {
|
|
Err = ERROR_DDS_SERVER_ALREADY_EXISTS;
|
|
break;
|
|
}
|
|
|
|
// Use the printable IP for the CN name
|
|
Err = CreateServerObject(
|
|
/* hDhcpC */ hDhcpC,
|
|
/* ServerName */ PrintableIp
|
|
);
|
|
if( ERROR_SUCCESS != Err ) { // dont add server if obj cant be created
|
|
break;
|
|
}
|
|
ServerLocation = MakeColumnName( PrintableIp );
|
|
ServerLocType = StoreGetChildType;
|
|
|
|
Err = StoreGetHandle( hDhcpC, 0, ServerLocType, ServerLocation, &hDhcpServer );
|
|
if( NO_ERROR == Err ) {
|
|
Err = DhcpDsAddServerInternal( hDhcpC, &hDhcpServer, Reserved, ServerLocation,
|
|
ServerName, ReservedPtr,
|
|
IpAddress, State );
|
|
StoreCleanupHandle( &hDhcpServer, 0 );
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
// clean up the allocated memory
|
|
MemArrayFree(&Servers, MemFreeFunc);
|
|
MemArrayCleanup( &Servers );
|
|
|
|
if( NULL != ServerLocation ) {
|
|
MemFree( ServerLocation );
|
|
}
|
|
|
|
DsAuthPrint(( L"DhcpDsAddServer() done\n" ));
|
|
return Err;
|
|
} // DhcpDsAddServer()
|
|
|
|
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 ServerLocation,// Container where this will go in
|
|
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;
|
|
BOOL fServerExists;
|
|
BOOL fServerDeleted;
|
|
|
|
if ( NULL == ServerLocation ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
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 for this object
|
|
(
|
|
/* 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;
|
|
|
|
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 );
|
|
fServerDeleted = TRUE;
|
|
break;
|
|
}
|
|
} // if
|
|
} // for
|
|
|
|
Require( fServerDeleted == TRUE );
|
|
|
|
if ( MemArraySize( &Servers ) > 0 ) {
|
|
// now set the new attrib list
|
|
Err = DhcpDsSetLists( DDS_RESERVED_DWORD, hDhcpRoot, &unused, &Servers,
|
|
NULL, NULL, NULL, NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL, NULL, NULL );
|
|
MemArrayFree(&Servers, MemFreeFunc);
|
|
} // if
|
|
else {
|
|
// this empty object needs to be deleted from the DS
|
|
|
|
Err = StoreDeleteThisObject( hDhcpC, DDS_RESERVED_DWORD,
|
|
StoreGetChildType,
|
|
ServerLocation );
|
|
} // else
|
|
|
|
return Err;
|
|
} // DhcpDsDelServerInternal()
|
|
|
|
//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, Loc;
|
|
ARRAY Servers;
|
|
PEATTRIB ThisAttrib;
|
|
WCHAR PrintableIp[ 20 ];
|
|
LPWSTR SearchFilter;
|
|
STORE_HANDLE hObj;
|
|
|
|
do {
|
|
|
|
Err = MemArrayInit( &Servers );
|
|
DsAuthPrint(( L"DhcpDelServer() \n" ));
|
|
|
|
ConvertAddressToLPWSTR( IpAddress, PrintableIp );
|
|
|
|
SearchFilter = MakeFilter( PrintableIp, ServerName, LDAP_OPERATOR_AND );
|
|
if ( NULL == SearchFilter ) {
|
|
Err = ERROR_INVALID_PARAMETER; // get a better error code
|
|
break;
|
|
}
|
|
|
|
DsAuthPrint(( L"DhcpDsDelServer() : Filter = %ws\n", SearchFilter ));
|
|
|
|
Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers,
|
|
SearchFilter );
|
|
MemFree( SearchFilter );
|
|
|
|
|
|
// GetListOfAllServersMatchingFilter() returns the dhcp servers
|
|
// defined the in all the maching objects, so it also returns false
|
|
// objects.
|
|
|
|
// Since we are using '&' operator for ip and host name, it will return
|
|
// a single object. However, that object may contain more than one entries
|
|
// in dhcpServers attribute.
|
|
|
|
if ( MemArraySize( &Servers ) == 0 ) {
|
|
Err = ERROR_DDS_SERVER_DOES_NOT_EXIST;
|
|
break;
|
|
}
|
|
|
|
// get the object CN. This is okay since it returns only one object.
|
|
Err = MemArrayInitLoc( &Servers, &Loc );
|
|
Err = MemArrayGetElement( &Servers, &Loc, &ThisAttrib );
|
|
|
|
Require( NULL != ThisAttrib );
|
|
Require( NULL != ThisAttrib->ADsPath );
|
|
|
|
// get a handle to the object that contains the server to be deleted
|
|
Err = StoreGetHandle( hDhcpC, DDS_RESERVED_DWORD,
|
|
StoreGetChildType, ThisAttrib->ADsPath,
|
|
&hObj );
|
|
if ( ERROR_SUCCESS != Err ) {
|
|
break;
|
|
}
|
|
|
|
// ADsPath is cn=xxxx, get rid of 'cn='
|
|
Err = DhcpDsDelServerInternal( hDhcpC, &hObj, Reserved,
|
|
ThisAttrib->ADsPath, ServerName,
|
|
ReservedPtr, IpAddress );
|
|
|
|
// Ignore the error
|
|
(void ) StoreCleanupHandle( &hObj, 0 );
|
|
|
|
} while ( FALSE );
|
|
|
|
// Free allocated memory
|
|
|
|
MemArrayFree( &Servers, MemFreeFunc );
|
|
|
|
DsAuthPrint(( L"DhcpDsDelServer() exiting...\n" ));
|
|
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, LDAP_OPERATOR_OR );
|
|
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 = MIDL_user_allocate(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()
|
|
|
|
//================================================================================
|
|
// end of file
|
|
//================================================================================
|