|
|
/*++
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;
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 = (PSTR)TraceAlloc(LPTR, 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) { TraceFree(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 = ERROR_SUCCESS; PWSTR FullDllPath = NULL; PWSTR computer_name = NULL; // Have to use a dll for dhcp authorization function.
// This code loads them.
HMODULE module = NULL; DWORD ( __stdcall *EnumServersFn )( DWORD, void* , DHCP_SERVER_INFO_ARRAY** ,void* ,void* ); DWORD ( __stdcall *AddServerFn )( DWORD, void* , DHCP_SERVER_INFO* ,void* ,void* ); FullDllPath = (PWSTR)TraceAlloc(LPTR, MAX_PATH*sizeof(WCHAR)); if( !FullDllPath ) { err = ERROR_NOT_ENOUGH_MEMORY; DebugMsg( "No Memory!\n" ); goto fail; }
if( !ExpandEnvironmentStrings(L"%systemroot%\\system32\\dhcpsapi.dll", FullDllPath, MAX_PATH) ) { err = GetLastError(); DebugMsg( "ExpandEnvironmentStrings failed! (0x%x)\n", err ); goto fail; }
module = LoadLibrary(FullDllPath); if (!module) { err = GetLastError(); DebugMsg( "LoadLibrary(dhcpsapi) failed, ec = %d\n", err ); goto fail; }
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; } // 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 = 0;
if ( !GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, computer_name, &computer_name_len ) && ERROR_MORE_DATA == GetLastError() ) { computer_name = (PWSTR)TraceAlloc(LPTR, computer_name_len * sizeof(WCHAR));
if ( NULL == 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; } DebugMsg( "ComputerName = %s\n", computer_name ); } else // shoudn�t hit this unless there are serious problems with the system.
{ err = GetLastError(); DebugMsg( "GetComputerNameEx failed, ec = %d\n", err ); goto fail; }
#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 = ERROR_FUNCTION_FAILED; 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) { TraceFree(computer_name); computer_name = NULL; }
if (module) { FreeLibrary(module); }
if (FullDllPath) { TraceFree(FullDllPath); } return HRESULT_FROM_WIN32( err ); }
|