/*++ 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 ); }