windows-nt/Source/XPSP1/NT/net/dhcp/server/dhcpds/upndown.c
2020-09-26 16:20:57 +08:00

645 lines
24 KiB
C

//================================================================================
// Copyright (C) 1997 Microsoft Corporation
// Author: RameshV
// Description: Download and Upload related code.
//================================================================================
//================================================================================
// includes
//================================================================================
#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 <rpcapi2.h>
#include <rpcstubs.h>
//================================================================================
// utilities
//================================================================================
//DOC DhcpDsServerGetLastUpdateTime gets the last update time for this server in the DS
DWORD
DhcpDsServerGetLastUpdateTime( // get last update time for server
IN LPSTORE_HANDLE hServer, // server to get last update time of
IN OUT LPFILETIME Time // set this struct appropriately
)
{
HRESULT Err;
DWORD nAttributes;
LPWSTR TimeAttrName; // attribute name for time..
PADS_ATTR_INFO Attributes;
SYSTEMTIME SysTime;
TimeAttrName = DHCP_ATTRIB_WHEN_CHANGED;
Attributes = NULL; nAttributes = 0;
Err = ADSIGetObjectAttributes // now read the last changed time attr
(
hServer->ADSIHandle,
&TimeAttrName,
1, // only 1 attribute in above array
&Attributes,
&nAttributes
);
if( FAILED(Err) || 0 == nAttributes || 0 == Attributes->dwNumValues ) {
if( Attributes ) {
FreeADsMem(Attributes);
return ERROR_GEN_FAILURE; // blanket error? maybe better err msg..
}
return ConvertHresult(Err);
}
if( Attributes->pADsValues[0].dwType != ADSTYPE_UTC_TIME ) {
FreeADsMem(Attributes);
return ERROR_GEN_FAILURE; // unexpected data format
}
SysTime = Attributes->pADsValues[0].UTCTime; // copy time structs
FreeADsMem(Attributes);
Err = SystemTimeToFileTime(&SysTime, Time); // try to convert to filetime struct
if( FAILED( Err ) ) return GetLastError(); // something went wrong?
return ERROR_SUCCESS;
}
BOOL _inline
AddressFoundInHostent(
IN DHCP_IP_ADDRESS AddrToSearch, // Host-Order addr
IN HOSTENT *ServerEntry // entry to search for..
)
{
ULONG nAddresses, ThisAddress;
if( NULL == ServerEntry ) return FALSE; // no address to search in
nAddresses = 0; // have a host entry to compare for addresses
while( ServerEntry->h_addr_list[nAddresses] ) {
ThisAddress = ntohl(*(DHCP_IP_ADDRESS*)ServerEntry->h_addr_list[nAddresses++] );
if( ThisAddress == AddrToSearch ) {
return TRUE; // yeah address matched.
}
}
return FALSE;
}
//================================================================================
// exports
//================================================================================
//BeginExport(function)
//DOC DhcpDsGetLastUpdateTime gets the last update time for the server
//DOC specified by name. If the server does not exist, or if server object doesnt
//DOC exist, then an error is returned. If the time value
//DOC does not exist on the server object, again, an error is returned.
DWORD
DhcpDsGetLastUpdateTime( // last update time for server
IN LPWSTR ServerName, // this is server of interest
IN OUT LPFILETIME Time // fill in this w./ the time
) //EndExport(function)
{
DWORD Err,i, LocType ;
LPDHCPDS_SERVERS Servers;
extern STORE_HANDLE hDhcpC, hDhcpRoot; // From rpcstubs.c
LPWSTR Location, LocStr;
BOOL Found;
STORE_HANDLE hServer;
HOSTENT *ServerEntry;
if( NULL == ServerName ) return ERROR_INVALID_PARAMETER;
do { // name to IP lookup
CHAR TmpBuf[300];
wcstombs(TmpBuf, ServerName, sizeof(TmpBuf)-1);
TmpBuf[sizeof(TmpBuf)-1] = '\0';
ServerEntry = gethostbyname(TmpBuf);
} while(0);
Servers = NULL;
Err = DhcpDsEnumServers // first get a list of servers
(
/* hDhcpC */ &hDhcpC, // frm rpcstubs.c, opened in DhcpDsInitDS
/* hDhcpRoot */ &hDhcpRoot, // ditto
/* Reserved */ DDS_RESERVED_DWORD,
/* ServersInfo */ &Servers
);
if( ERROR_SUCCESS != Err ) {
Time->dwLowDateTime = Time->dwHighDateTime = 0;
return Err; // error.. return w/ no time
}
Found = FALSE;
LocStr = Location = NULL; // initialize..
for( i = 0; i < Servers->NumElements ; i ++ ) {
if( 0 != _wcsicmp(ServerName, Servers->Servers[i].ServerName) &&
!AddressFoundInHostent(Servers->Servers[i].ServerAddress, ServerEntry) ) {
continue; // ughm.. not the same server..
} else { // ok got the server
Location = Servers->Servers[i].DsLocation;
LocType = Servers->Servers[i].DsLocType;
Found = TRUE;
if( NULL != Location ) break;
}
}
if( ! Found ) { // could not find server in list..?
MemFree(Servers);
return ERROR_FILE_NOT_FOUND;
}
if( NULL == Location ) { // could not find server location?
MemFree(Servers); // dont need this anymore
Servers = NULL;
Location = MakeColumnName(ServerName); // just presume it is under hDhcpC container
LocType = StoreGetChildType; // child type
if( NULL == Location ) return ERROR_NOT_ENOUGH_MEMORY;
}
Err = StoreGetHandle // now try to open the server object
(
/* hStore */ &hDhcpC,
/* Reserved */ DDS_RESERVED_DWORD,
/* StoreGetType */ LocType,
/* Path */ Location,
/* hStoreOut */ &hServer
);
if( Servers ) { // Location points into this
MemFree(Servers); // freeing this also free Location
} else { // Location is allocated memory
MemFree(Location);
}
if( ERROR_SUCCESS != Err ) return Err; // some DS trouble?
Err = DhcpDsServerGetLastUpdateTime(&hServer, Time);
(void)StoreCleanupHandle(&hServer, 0); // assume this wont fail.
return Err;
}
//DOC ServerUploadClasses does rpc calls to server and copies stuff over to DS.
DWORD
ServerUploadClasses( // upload classes info to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress // server ip address
)
{
DWORD Err, Resume, PrefMax, i, nRead, nTotal;
LPDHCP_CLASS_INFO_ARRAY ClassesInfo;
Resume = 0; PrefMax = 0xFFFFFFFF; nRead = nTotal = 0;
ClassesInfo = NULL;
Err = DhcpEnumClasses(ServerAddress, 0, &Resume, PrefMax, &ClassesInfo, &nRead, &nTotal);
if( ERROR_NO_MORE_ITEMS == Err ) return ERROR_SUCCESS;
if( ERROR_SUCCESS != Err ) return Err; // could not enumerate classes.
for( i = 0; i < ClassesInfo->NumElements; i ++ ) {
Err = DhcpCreateClassDS(ServerAddress, 0, &ClassesInfo->Classes[i]);
if( ERROR_SUCCESS != Err ) break;
#if 0
Err = ServerUploadOptDefsForClass(
hDhcpC,
hServer,
ServerAddress,
ClassesInfo->Classes[i].ClassName
);
if( ERROR_SUCCESS != Err ) break;
#endif
}
if( ClassesInfo ) MemFree(ClassesInfo);
return Err;
}
//DOC ServerUploadOptdefs does rpc calls to server and copies stuff over to DS
DWORD
ServerUploadOptdefs( // upload opt defs info to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress // server ip address
)
{
DWORD Err, i;
LPDHCP_ALL_OPTIONS Options;
Options = NULL;
Err = DhcpGetAllOptions(ServerAddress,0, &Options);
if( ERROR_NO_MORE_ITEMS == Err ) return ERROR_SUCCESS;
if( ERROR_SUCCESS != Err ) return Err;
if( Options->NonVendorOptions ) {
for( i = 0; i < Options->NonVendorOptions->NumElements; i ++ ) {
Err = DhcpCreateOptionV5DS(
ServerAddress,
0,
Options->NonVendorOptions->Options[i].OptionID,
NULL /* no class */,
NULL /* no vendor */,
&Options->NonVendorOptions->Options[i]
);
if( ERROR_SUCCESS != Err ) break;
}
}
if( ERROR_SUCCESS != Err ) {
MemFree(Options);
return Err;
}
for( i = 0; i < Options->NumVendorOptions; i ++ ) {
Err = DhcpCreateOptionV5DS(
ServerAddress,
DHCP_FLAGS_OPTION_IS_VENDOR,
Options->VendorOptions[i].Option.OptionID,
Options->VendorOptions[i].ClassName,
Options->VendorOptions[i].VendorName,
&Options->VendorOptions[i].Option
);
if( ERROR_SUCCESS != Err ) break;
}
if( ERROR_SUCCESS != Err ) {
MemFree(Options);
return Err;
}
if( Options ) MemFree(Options);
return Err;
}
//DOC UploadOptiosn does rpc calls to server and copies stuff over to DS
UploadOptions( // upload options to DS
IN LPWSTR ServerAddress,
IN LPDHCP_OPTION_SCOPE_INFO ScopeInfo
)
{
DWORD Err, Resume, PrefMax, i, nRead, nTotal;
LPDHCP_ALL_OPTION_VALUES Options;
Resume = 0; PrefMax = 0xFFFFFFFF; nRead = nTotal = 0;
Options = NULL;
Err = DhcpGetAllOptionValues( // get list of default opt values
ServerAddress,
0,
ScopeInfo,
&Options
);
if( ERROR_NO_MORE_ITEMS == Err ) return ERROR_SUCCESS;
if( ERROR_SUCCESS != Err ) return Err; // oops could not do this simple task?
for( i = 0; i < Options->NumElements; i ++ ) {// now try to set each list of options..
if( NULL == Options->Options[i].OptionsArray ) {
continue; // uh? another way to say no options..
}
Err = DhcpSetOptionValuesV5DS (
ServerAddress,
Options->Options[i].IsVendor? DHCP_FLAGS_OPTION_IS_VENDOR:0,
Options->Options[i].ClassName,
Options->Options[i].VendorName,
ScopeInfo,
Options->Options[i].OptionsArray
);
if( ERROR_SUCCESS != Err ) {
MemFree(Options);
return Err;
}
}
return ERROR_SUCCESS; // saved it
}
//DOC ServerUploadOptions does rpc calls to server and copies stuff over to DS
DWORD
ServerUploadOptions( // upload options info to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress // server ip address
)
{
DWORD Err;
DHCP_OPTION_SCOPE_INFO ScopeInfo;
#if 0
ScopeInfo.ScopeInfo.DefaultScopeInfo = NULL;
ScopeInfo.ScopeType = DhcpDefaultOptions;
Err = UploadOptions(ServerAddress, &ScopeInfo);
if( ERROR_SUCCESS != Err ) return Err; // could not save default options..
#endif
ScopeInfo.ScopeType = DhcpGlobalOptions;
ScopeInfo.ScopeInfo.GlobalScopeInfo = NULL;
Err = UploadOptions(ServerAddress, &ScopeInfo);
if( ERROR_SUCCESS != Err ) return Err; // could not save global options..
return ERROR_SUCCESS;
}
//DOC ReservationUploadOptions does rpc calls to server and copies stuff to DS
DWORD
ReservationUploadOptions( // upload reservation options to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress, // server ip address
IN DWORD SubnetAddress, // add of subnet to add
IN DWORD ReserveAddress // address of reservation
)
{
DHCP_OPTION_SCOPE_INFO ScopeInfo;
ScopeInfo.ScopeType = DhcpReservedOptions;
ScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = SubnetAddress;
ScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = ReserveAddress;
return UploadOptions(ServerAddress, &ScopeInfo);
}
//DOC SubnetUploadOptions does rpc calls to server and copies stuff to DS
DWORD
SubnetUploadOptions( // upload subnet options to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress, // server ip address
IN DWORD SubnetAddress // add of subnet to add
)
{
DHCP_OPTION_SCOPE_INFO ScopeInfo;
ScopeInfo.ScopeType = DhcpSubnetOptions;
ScopeInfo.ScopeInfo.SubnetScopeInfo = SubnetAddress;
return UploadOptions(ServerAddress, &ScopeInfo);
}
//DOC ServerUploadSubnet does rpc calls to server and copies stuff over to DS
DWORD
ServerUploadSubnet( // upload subnet and relevant info to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress, // server ip address
IN DWORD SubnetAddress // add of subnet to add
)
{
DWORD Err, Resume, PrefMax, i, nRead, nTotal;
LPDHCP_SUBNET_INFO SubnetInfo;
DHCP_SUBNET_ELEMENT_TYPE SubnetEltType;
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 EltInfo;
LPDHCP_SUPER_SCOPE_TABLE SScopeTbl;
Err = DhcpGetSubnetInfo(ServerAddress, SubnetAddress, &SubnetInfo);
if( ERROR_SUCCESS != Err ) return Err; // could not get subnet info..
Err = DhcpCreateSubnetDS(ServerAddress, SubnetAddress, SubnetInfo);
if( SubnetInfo ) MemFree(SubnetInfo);
if( ERROR_SUCCESS != Err ) return Err; // could not save onto DS
SScopeTbl = NULL;
Err = DhcpGetSuperScopeInfoV4( // get superscope table
ServerAddress,
&SScopeTbl
);
if( ERROR_SUCCESS == Err ) { // could get superscope table
for( i = 0; i < SScopeTbl->cEntries ; i ++ ) {
if( SScopeTbl->pEntries[i].SubnetAddress == SubnetAddress ) {
Err = DhcpSetSuperScopeV4DS(
ServerAddress,
SubnetAddress,
SScopeTbl->pEntries[i].SuperScopeName,
TRUE /* change superscope if it exists..*/
);
break;
}
}
MemFree(SScopeTbl);
if( ERROR_SUCCESS != Err ) return Err; // could not set superscope..
}
Resume = 0; PrefMax = 0xFFFFFFFF;
EltInfo = NULL; nRead = nTotal = 0;
Err = DhcpEnumSubnetElementsV4( // enumerate ranges
ServerAddress,
SubnetAddress,
DhcpIpRanges,
&Resume,
PrefMax,
&EltInfo,
&nRead,
&nTotal
);
if( ERROR_SUCCESS != Err ) return Err; // could not get ranges
for( i = 0; i < EltInfo->NumElements; i ++ ) {// try to add each range
Err = DhcpAddSubnetElementV4DS(
ServerAddress,
SubnetAddress,
&EltInfo->Elements[i]
);
if( ERROR_SUCCESS != Err ) break;
}
if( EltInfo ) MemFree(EltInfo); // free-up memory
if( ERROR_SUCCESS != Err ) return Err; // could not add ranges
Resume = 0; PrefMax = 0xFFFFFFFF;
EltInfo = NULL;
Err = DhcpEnumSubnetElementsV4( // enumerate reservations
ServerAddress,
SubnetAddress,
DhcpReservedIps,
&Resume,
PrefMax,
&EltInfo,
&nRead,
&nTotal
);
if( ERROR_NO_MORE_ITEMS == Err ) goto try_Excl;
if( ERROR_SUCCESS != Err ) return Err; // could not get exclusions
for( i = 0; i < EltInfo->NumElements; i ++ ) {// try to add each reservation
Err = DhcpAddSubnetElementV4DS(
ServerAddress,
SubnetAddress,
&EltInfo->Elements[i]
);
if( ERROR_SUCCESS != Err ) break; // could not add reseration in DS
Err = ReservationUploadOptions(
hDhcpC,
hServer,
ServerAddress,
SubnetAddress,
EltInfo->Elements[i].Element.ReservedIp->ReservedIpAddress
);
if( ERROR_SUCCESS != Err ) break; // could not add reservaation options
}
if( EltInfo ) MemFree(EltInfo); // free-up memory
if( ERROR_SUCCESS != Err ) return Err; // could not add exclusions
try_Excl:
Resume = 0; PrefMax = 0xFFFFFFFF;
EltInfo = NULL;
Err = DhcpEnumSubnetElementsV4( // enumerate exclusions
ServerAddress,
SubnetAddress,
DhcpReservedIps,
&Resume,
PrefMax,
&EltInfo,
&nRead,
&nTotal
);
if( ERROR_NO_MORE_ITEMS == Err ) goto try_Options;
if( ERROR_SUCCESS != Err ) return Err; // could not get exclusions
for( i = 0; i < EltInfo->NumElements; i ++ ) {// try to add each exclusion
Err = DhcpAddSubnetElementV4DS(
ServerAddress,
SubnetAddress,
&EltInfo->Elements[i]
);
if( ERROR_SUCCESS != Err ) break;
}
if( EltInfo ) MemFree(EltInfo); // free-up memory
if( ERROR_SUCCESS != Err ) return Err; // could not add exclusions
try_Options:
return SubnetUploadOptions(hDhcpC,hServer,ServerAddress,SubnetAddress);
}
//DOC ServerUploadSubnets does rpc calls to server and copies stuff over to DS
DWORD
ServerUploadSubnets( // upload subnets info to DS
IN OUT LPSTORE_HANDLE hDhcpC, // dhcp container to store at
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerAddress // server ip address
)
{
DWORD Err, Resume, PrefMax, i, nRead, nTotal;
LPDHCP_IP_ARRAY Subnets;
Resume = 0; PrefMax = 0xFFFFFFFF; nRead = nTotal = 0;
Subnets = NULL;
Err = DhcpEnumSubnets(ServerAddress, &Resume, PrefMax, &Subnets, &nRead, &nTotal);
if( ERROR_NO_MORE_ITEMS == Err ) return ERROR_SUCCESS;
if( ERROR_SUCCESS != Err ) return Err; // could not get list of elements?
for( i = 0; i < Subnets->NumElements ; i ++ ) {
Err = ServerUploadSubnet(hDhcpC, hServer, ServerAddress, Subnets->Elements[i]);
if( ERROR_SUCCESS != Err ) break;
}
if( Subnets ) MemFree(Subnets);
return Err;
}
//DOC UploadServer downloads the server info by making RPC calls..
DWORD
UploadServer( // make rpc calls and pull up info to DS.
IN OUT LPSTORE_HANDLE hDhcpC, // general container where info is stored
IN OUT LPSTORE_HANDLE hServer, // server obj in DS
IN LPWSTR ServerName, // name of server
IN DWORD IpAddress // ip address of server
)
{
DWORD Err;
LPSTR IpAddrStr;
WCHAR ServerAddress[sizeof("000.000.000.000")];
IpAddress = htonl(IpAddress); // use n/w order ip address..
IpAddrStr = inet_ntoa(*(struct in_addr *)&IpAddress);
Err = mbstowcs(ServerAddress, IpAddrStr, ( sizeof(ServerAddress)/sizeof( WCHAR ) ) );
if( -1 == Err ) { // could not convert to LPWSTR
return ERROR_GEN_FAILURE;
}
Err = ServerUploadClasses(hDhcpC, hServer, ServerAddress);
if( ERROR_SUCCESS != Err ) { // could not upload server classes info
return Err;
}
Err = ServerUploadOptdefs(hDhcpC, hServer, ServerAddress);
if( ERROR_SUCCESS != Err ) { // could not upload option defs ?
return Err;
}
Err = ServerUploadOptions(hDhcpC, hServer, ServerAddress);
if( ERROR_SUCCESS != Err ) { // could not upload options?
return Err;
}
Err = ServerUploadSubnets(hDhcpC, hServer, ServerAddress);
if( ERROR_SUCCESS != Err ) { // could not upload subnets?
return Err;
}
return ERROR_SUCCESS;
}
//BeginExport(function)
//DOC AddServer 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
AddServer( // 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 to server object
IN DWORD IpAddress, // IpAddress to add to server
IN DWORD State // state of server
) //EndExport(function)
{
DWORD Err, Err2;
STORE_HANDLE hServer;
Err = StoreGetHandle( // get the server obj..
hDhcpC,
DDS_RESERVED_DWORD,
StoreGetChildType,
ADsPath,
&hServer
);
if( ERROR_SUCCESS != Err ) return Err; // could be because server obj elsewhere??
if( !CFLAG_DONT_DO_DSWORK ) { // if DS stuff is enabled in the first place
Err = UploadServer(hDhcpC, &hServer, ServerName, IpAddress);
}
StoreCleanupHandle(&hServer, 0); // cleanup this server..
return Err;
}
//================================================================================
// end of file
//================================================================================