windows-nt/Source/XPSP1/NT/base/remoteboot/rbsetup/server/dhcp.cpp
2020-09-26 16:20:57 +08:00

313 lines
9.7 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dhcp.cpp
Abstract:
Code to allow RIS to automatically authorize for DHCP.
Author:
Hugh Leather (hughleat) 25-July-2000
Revision History:
--*/
#include "pch.h"
#include "dhcpapi.h"
#include "dhcp.h"
#include "setup.h"
DEFINE_MODULE("DHCP");
PSTR
pSetupUnicodeToMultiByte(
IN PCWSTR UnicodeString,
IN UINT Codepage
)
/*++
Routine Description:
Convert a string from unicode to ansi.
Arguments:
UnicodeString - supplies string to be converted.
Codepage - supplies codepage to be used for the conversion.
Return Value:
NULL if out of memory or invalid codepage.
Caller can free buffer with pSetupFree().
--*/
{
UINT WideCharCount;
PSTR String;
UINT StringBufferSize;
UINT BytesInString;
PSTR p;
WideCharCount = lstrlenW(UnicodeString) + 1;
//
// Allocate maximally sized buffer.
// If every unicode character is a double-byte
// character, then the buffer needs to be the same size
// as the unicode string. Otherwise it might be smaller,
// as some unicode characters will translate to
// single-byte characters.
//
StringBufferSize = WideCharCount * 2;
String = new char[StringBufferSize];
if(String == NULL) {
return(NULL);
}
//
// Perform the conversion.
//
BytesInString = WideCharToMultiByte(
Codepage,
0, // default composite char behavior
UnicodeString,
WideCharCount,
String,
StringBufferSize,
NULL,
NULL
);
if(BytesInString == 0) {
delete(String);
return(NULL);
}
return(String);
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Dhcp Authorization
// ------------------
// Authorization works like this:
// S <- List of authorized servers (from call to DhcpEnumServers)
// I <- IP addresses for this machine (from gethostaddr( 0 ))
// c <- fully qualified physical DNS name of local machine (from GetComputerNameEx)
// for each i such that i is a member of I and i is not a member of S do
// Authorize( i, c ) (by a call to DhcpAddServer)
//
// Aurguments
// hDlg
// Parent window (only used for displaying message boxes modally). Can be NULL.
//
// Returns
// Whatever error code is first generated (or ERROR_SUCCESS if none). A message box will
// be displayed if there is an error.
//
// Used By
// This code is only used by dialogs.cpp
//////////////////////////////////////////////////////////////////////////////////////////////
HRESULT AuthorizeDhcp( HWND hDlg ) {
DWORD err;
PWCHAR computer_name = 0;
// Have to use a dll for dhcp authorization function.
// This code loads them.
HMODULE module;
DWORD ( __stdcall *EnumServersFn )( DWORD, void* , DHCP_SERVER_INFO_ARRAY** ,void* ,void* );
DWORD ( __stdcall *AddServerFn )( DWORD, void* , DHCP_SERVER_INFO* ,void* ,void* );
module = LoadLibraryA( "dhcpsapi.dll" );
if( module ) {
EnumServersFn = ( DWORD ( __stdcall * )( DWORD, void* , DHCP_SERVER_INFO_ARRAY** ,void* ,void* )) GetProcAddress( module, "DhcpEnumServers" );
if( !EnumServersFn ) {
err = GetLastError();
DebugMsg( "GetProcAddress(DhcpEnumServers) failed, ec = %d\n", err );
goto fail;
}
AddServerFn = ( DWORD ( __stdcall * )( DWORD, void* , DHCP_SERVER_INFO* ,void* ,void* )) GetProcAddress( module, "DhcpAddServer" );
if( !AddServerFn ) {
err = GetLastError();
DebugMsg( "GetProcAddress(DhcpAddServer) failed, ec = %d\n", err );
goto fail;
}
}
else {
err = GetLastError();
DebugMsg( "LoadLibrary failed, ec = %d\n", err );
goto fail;
}
// We need the list of ip addresses associated with this machine. This we do through sockets.
HOSTENT* host;
#if 0
DWORD ip;
ip = 0;
host = gethostbyaddr(( const char* )&ip, sizeof( DWORD ), AF_INET );
if( host == NULL ) {
err = WSAGetLastError();
DebugMsg( "gethostbyaddr failed, ec = %d\n", err );
goto fail;
}
if( host->h_addrtype != AF_INET || host->h_length != sizeof( DWORD )) {
err = E_FAIL;
DebugMsg( "gethostbyaddr returned invalid data\n" );
goto fail;
}
#endif
// We get the entire list of dhcp servers.
DHCP_SERVER_INFO_ARRAY* _servers;
if(( err = EnumServersFn( 0, NULL, &_servers, NULL, NULL )) != ERROR_SUCCESS ) {
//
// if this API fails, it will fail with a private DCHP error code that has
// no win32 mapping. So set the error code to something generic and
// reasonable.
//
DebugMsg( "DhcpEnumServers failed, ec = %d\n", err );
err = ERROR_DS_GENERIC_ERROR;
goto fail;
}
// We will need the name of the machine if we have to authorize it. Get the physical name as I'm not sure I trust what happens in the
// clustered case.
DWORD computer_name_len;
computer_name_len = MAX_COMPUTERNAME_LENGTH * 2; // Allow for extra DNS characters.
computer_name = new WCHAR[ MAX_COMPUTERNAME_LENGTH * 2 ];
if (!computer_name) {
err = ERROR_NOT_ENOUGH_MEMORY;
DebugMsg( "new failed, ec = %d\n", err );
goto fail;
}
if( !GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, computer_name, &computer_name_len )) {
err = GetLastError();
if( err == ERROR_MORE_DATA ) {
delete [] computer_name;
computer_name = new WCHAR[ computer_name_len ];
if (!computer_name) {
err = ERROR_NOT_ENOUGH_MEMORY;
DebugMsg( "new failed, ec = %d\n", err );
goto fail;
}
if( !GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, computer_name, &computer_name_len )) {
err = GetLastError();
DebugMsg( "GetComputerNameEx failed, ec = %d\n", err );
goto fail;
}
}
else goto fail;
}
DebugMsg( "ComputerName = %s\n", computer_name );
#if 1
char ComputerNameA[400];
DWORD ip;
WideCharToMultiByte(CP_ACP,
0, // default composite char behavior
computer_name,
-1,
ComputerNameA,
400,
NULL,
NULL
);
host = gethostbyname( ComputerNameA );
if( host == NULL ) {
err = WSAGetLastError();
DebugMsg( "gethostbyaddr failed, ec = %d\n", err );
goto fail;
}
if( host->h_addrtype != AF_INET || host->h_length != sizeof( DWORD )) {
err = E_FAIL;
DebugMsg( "gethostbyaddr returned invalid data\n" );
goto fail;
}
#endif
// Cool now that we have all of that jazz, we can check that each of our ip addresses is authorized.
for( PCHAR* i = host->h_addr_list; *i != 0; ++i ) {
ip = ntohl( *( DWORD* )*i );
DebugMsg( "searching server list for %d.%d.%d.%d\n",
ip & 0xFF,
(ip >> 8) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 24) & 0xFF );
BOOL this_address_authorized = FALSE;
for( unsigned j = 0; j < _servers->NumElements; ++j ) {
DebugMsg( "server list entry: %d.%d.%d.%d\n",
_servers->Servers[ j ].ServerAddress & 0xFF,
(_servers->Servers[ j ].ServerAddress >> 8) & 0xFF,
(_servers->Servers[ j ].ServerAddress >> 16) & 0xFF,
(_servers->Servers[ j ].ServerAddress >> 24) & 0xFF );
if( _servers->Servers[ j ].ServerAddress == ip ) {
DebugMsg("found a match in list\n");
this_address_authorized = TRUE;
err = ERROR_SUCCESS;
break;
}
}
if( !this_address_authorized ) {
// Authorize it!
DHCP_SERVER_INFO server_info = { 0 };
server_info.ServerAddress = ip;
server_info.ServerName = computer_name;
DebugMsg("authorizing %s (%d.%d.%d.%d)\n",
server_info.ServerName,
server_info.ServerAddress & 0xFF,
(server_info.ServerAddress >> 8) & 0xFF,
(server_info.ServerAddress >> 16) & 0xFF,
(server_info.ServerAddress >> 24) & 0xFF);
err = AddServerFn( 0, NULL, &server_info, NULL, NULL );
if( err != ERROR_SUCCESS ) {
//
// if this API fails, it will fail with a private DCHP error code that has
// no win32 mapping. So set the error code to something generic and
// reasonable.
//
DebugMsg("DhcpAddServer failed, ec = %d\n",
err
);
err = ERROR_DS_GENERIC_ERROR;
goto fail;
}
} else {
DebugMsg("skipping authorization of interface, it's already authorized\n");
}
}
err = ERROR_SUCCESS;
goto exit;
fail :
MessageBoxFromStrings(
hDlg,
IDS_AUTHORIZING_DHCP,
IDS_AUTHORIZE_DHCP_FAILURE,
MB_OK | MB_ICONERROR );
exit :
if (computer_name) {
delete [] computer_name;
}
return HRESULT_FROM_WIN32( err );
}