1471 lines
39 KiB
C++
1471 lines
39 KiB
C++
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
sockreg.cxx
|
||
|
||
Abstract:
|
||
|
||
Contains the registry/ini-file specific functions from gethost.c
|
||
|
||
Taken from Win95 Winsock 1.1 project
|
||
|
||
Contents:
|
||
SockGetSingleValue
|
||
(CheckRegistryForParameter)
|
||
(GetDnsServerListFromDhcp)
|
||
(GetDomainNameFromDhcp)
|
||
(GetDhcpHardwareInfo)
|
||
(OpenDhcpVxdHandle)
|
||
(DhcpVxdRequest)
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 10-Feb-1994
|
||
|
||
Environment:
|
||
|
||
Win32 user-mode DLL
|
||
|
||
Revision History:
|
||
|
||
10-Feb-1994 (rfirth)
|
||
Created
|
||
|
||
--*/
|
||
|
||
//
|
||
// includes
|
||
//
|
||
|
||
|
||
#include <wininetp.h>
|
||
#include "aproxp.h"
|
||
|
||
|
||
|
||
//
|
||
// manifests
|
||
//
|
||
|
||
#define PLATFORM_TYPE_UNKNOWN ((DWORD)(-1))
|
||
#define PLATFORM_TYPE_WIN95 ((DWORD)(0))
|
||
#define PLATFORM_TYPE_WINNT ((DWORD)(1))
|
||
|
||
#define PLATFORM_SUPPORTS_UNICODE 0x00000001
|
||
#define DEVICE_PREFIX "\\Device\\"
|
||
|
||
|
||
//
|
||
// manifests
|
||
//
|
||
|
||
//
|
||
// macros
|
||
//
|
||
|
||
#define FSTRLEN(p) lstrlen((LPSTR)(p))
|
||
#define FSTRCPY(p1, p2) lstrcpy((LPSTR)(p1), (LPSTR)(p2))
|
||
#define FSTRCAT(p1, p2) lstrcat((LPSTR)(p1), (LPSTR)(p2))
|
||
|
||
//
|
||
// MAP_PARAMETER_ID - returns a string corresponding to the database parameter
|
||
//
|
||
// N.B. id MUST start at 1
|
||
//
|
||
|
||
#define MAP_PARAMETER_ID(id) ParameterNames[(id) - 1]
|
||
|
||
//
|
||
// globally available registry keys
|
||
//
|
||
|
||
extern HKEY ServicesKey; // = INVALID_HANDLE_VALUE;
|
||
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
UINT
|
||
CheckRegistryForParameter(
|
||
IN UINT ParameterId,
|
||
OUT LPBYTE Data,
|
||
IN UINT DataLength
|
||
);
|
||
|
||
PRIVATE
|
||
UINT
|
||
GetDnsServerListFromDhcp(
|
||
LPBYTE Data,
|
||
UINT DataLength
|
||
);
|
||
|
||
PRIVATE
|
||
UINT
|
||
GetDomainNameFromDhcp(
|
||
LPBYTE Data,
|
||
UINT DataLength
|
||
);
|
||
|
||
PRIVATE
|
||
LPDHCP_QUERYINFO
|
||
GetDhcpHardwareInfo(
|
||
VOID
|
||
);
|
||
|
||
PRIVATE
|
||
DWORD_PTR
|
||
OpenDhcpVxdHandle(
|
||
VOID
|
||
);
|
||
|
||
PRIVATE
|
||
WORD
|
||
DhcpVxdRequest(
|
||
IN DWORD_PTR Handle,
|
||
IN WORD Request,
|
||
IN WORD BufferLength,
|
||
OUT LPVOID Buffer
|
||
);
|
||
|
||
PRIVATE
|
||
DWORD_PTR
|
||
OsOpenVxdHandle(
|
||
CHAR * VxdName,
|
||
WORD VxdId
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
OsCloseVxdHandle(
|
||
DWORD_PTR VxdHandle
|
||
);
|
||
|
||
PRIVATE
|
||
INT
|
||
OsSubmitVxdRequest(
|
||
DWORD_PTR VxdHandle,
|
||
INT OpCode,
|
||
LPVOID Param,
|
||
INT ParamLength
|
||
);
|
||
|
||
//
|
||
// private data
|
||
//
|
||
|
||
//
|
||
// ParameterNames - the names of the registry values corresponding to the
|
||
// variables retrieved by SockGetSingleValue.
|
||
//
|
||
// N.B. These MUST be in order of the CONFIG_ manifests in sockreg.h
|
||
//
|
||
|
||
PRIVATE const LPCSTR ParameterNames[] = {
|
||
"HostName",
|
||
"Domain",
|
||
"SearchList",
|
||
"NameServer"
|
||
};
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* GetBoundAdapterList
|
||
*
|
||
* Gets a list of names of all adapters bound to a protocol (TCP/IP). Returns
|
||
* a pointer to an array of pointers to strings - basically an argv list. The
|
||
* memory for the strings is concatenated to the array and the array is NULL
|
||
* terminated. If Elnkii1 and IbmTok2 are bound to TCP/IP then this function
|
||
* will return:
|
||
*
|
||
* ---> addr of string1 \
|
||
* addr of string2 \
|
||
* NULL > allocated as one block
|
||
* &string1: "Elnkii1" /
|
||
* &string2: "IbmTok2" /
|
||
*
|
||
* ENTRY BindingsSectionKey
|
||
* - Open registry handle to a linkage key (e.g. Tcpip\Linkage)
|
||
*
|
||
* EXIT
|
||
*
|
||
* RETURNS pointer to argv[] style array, or NULL
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
LPSTR* GetBoundAdapterList(HKEY BindingsSectionKey)
|
||
{
|
||
|
||
LPSTR* resultBuffer;
|
||
|
||
LONG err;
|
||
DWORD valueType;
|
||
PBYTE valueBuffer = NULL;
|
||
DWORD valueLength;
|
||
LPSTR* nextResult;
|
||
int len;
|
||
DWORD resultLength;
|
||
LPSTR nextValue;
|
||
LPSTR variableData;
|
||
DWORD numberOfBindings;
|
||
|
||
//
|
||
// get required size of value buffer
|
||
//
|
||
|
||
valueLength = 0;
|
||
resultBuffer = NULL;
|
||
|
||
err = RegQueryValueEx(BindingsSectionKey,
|
||
"Bind",
|
||
NULL, // reserved
|
||
&valueType,
|
||
NULL,
|
||
&valueLength
|
||
);
|
||
if (err != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
if (valueType != REG_MULTI_SZ) {
|
||
goto quit;
|
||
}
|
||
if (!valueLength) {
|
||
goto quit;
|
||
}
|
||
valueBuffer = (PBYTE)ALLOCATE_MEMORY(LPTR, valueLength);
|
||
if ( valueBuffer == NULL ) {
|
||
goto quit;
|
||
}
|
||
|
||
err = RegQueryValueEx(BindingsSectionKey,
|
||
"Bind",
|
||
NULL, // reserved
|
||
&valueType,
|
||
valueBuffer,
|
||
&valueLength
|
||
);
|
||
if (err != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
resultLength = sizeof(LPSTR); // the NULL at the end of the list
|
||
numberOfBindings = 0;
|
||
nextValue = (LPSTR)valueBuffer;
|
||
while (len = strlen(nextValue)) {
|
||
resultLength += sizeof(LPSTR) + len + 1;
|
||
if (!_strnicmp(nextValue, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
|
||
resultLength -= sizeof(DEVICE_PREFIX) - 1;
|
||
}
|
||
nextValue += len + 1;
|
||
++numberOfBindings;
|
||
}
|
||
resultBuffer = (LPSTR*)ALLOCATE_MEMORY(LPTR, resultLength);
|
||
if ( resultBuffer == NULL ) {
|
||
goto quit;
|
||
}
|
||
nextValue = (LPSTR)valueBuffer;
|
||
nextResult = resultBuffer;
|
||
variableData = (LPSTR)(((LPSTR*)resultBuffer) + numberOfBindings + 1);
|
||
while (numberOfBindings--) {
|
||
|
||
LPSTR adapterName;
|
||
|
||
adapterName = nextValue;
|
||
if (!_strnicmp(adapterName, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
|
||
adapterName += sizeof(DEVICE_PREFIX) - 1;
|
||
}
|
||
*nextResult++ = variableData;
|
||
strcpy(variableData, adapterName);
|
||
while (*variableData) {
|
||
++variableData;
|
||
}
|
||
++variableData;
|
||
while (*nextValue) {
|
||
++nextValue;
|
||
}
|
||
++nextValue;
|
||
}
|
||
|
||
*nextResult = NULL;
|
||
|
||
quit:
|
||
|
||
if ( valueBuffer != NULL )
|
||
{
|
||
FREE_MEMORY(valueBuffer);
|
||
}
|
||
|
||
return resultBuffer;
|
||
}
|
||
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* OpenAdapterKey
|
||
*
|
||
* Opens one of the 2 per-adapter registry keys: <Adapter>\Parameters\Tcpip, or
|
||
* NetBT\Adapters\<Adapter>
|
||
*
|
||
* ENTRY KeyType - KEY_TCP or KEY_NBT
|
||
* Name - pointer to adapter name to use
|
||
* Key - pointer to returned key
|
||
*
|
||
* EXIT Key updated
|
||
*
|
||
* RETURNS TRUE if success
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
BOOL OpenAdapterKey(DWORD KeyType, LPSTR Name, PHKEY Key)
|
||
{
|
||
|
||
LONG err;
|
||
CHAR keyName[MAX_ADAPTER_NAME_LENGTH + sizeof("\\Parameters\\Tcpip")];
|
||
|
||
if ((lstrlen(Name)+sizeof("\\Parameters\\Tcpip")) < ARRAY_ELEMENTS(keyName))
|
||
{
|
||
if (KeyType == KEY_TCP) {
|
||
|
||
//
|
||
// open the handle to this adapter's TCPIP parameter key
|
||
//
|
||
|
||
strcpy(keyName, Name);
|
||
strcat(keyName, "\\Parameters\\Tcpip");
|
||
} else if (KeyType == KEY_NBT) {
|
||
|
||
//
|
||
// open the handle to the NetBT\Adapters\<Adapter> handle
|
||
//
|
||
|
||
strcpy(keyName, "NetBT\\Adapters\\");
|
||
strcat(keyName, Name);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
INET_ASSERT((lstrlen(Name)+sizeof("\\Parameters\\Tcpip")) < ARRAY_ELEMENTS(keyName));
|
||
return FALSE;
|
||
}
|
||
|
||
err = REGOPENKEY(ServicesKey,
|
||
keyName,
|
||
Key
|
||
);
|
||
|
||
|
||
DEBUG_PRINT( SOCKETS,
|
||
INFO,
|
||
("RegOpenKey %s %s %s %d\n",
|
||
SERVICES_KEY_NAME, keyName,
|
||
(err != ERROR_SUCCESS )? "failed":"success",
|
||
GetLastError() ));
|
||
|
||
|
||
return (err == ERROR_SUCCESS);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* ReadRegistryDword
|
||
*
|
||
* Reads a registry value that is stored as a DWORD
|
||
*
|
||
* ENTRY Key - open registry key where value resides
|
||
* ParameterName - name of value to read from registry
|
||
* Value - pointer to returned value
|
||
*
|
||
* EXIT *Value = value read
|
||
*
|
||
* RETURNS TRUE if success
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
BOOL ReadRegistryDword(HKEY Key, LPSTR ParameterName, LPDWORD Value)
|
||
{
|
||
|
||
LONG err;
|
||
DWORD valueLength;
|
||
DWORD valueType;
|
||
|
||
valueLength = sizeof(*Value);
|
||
|
||
err = RegQueryValueEx(Key,
|
||
ParameterName,
|
||
NULL, // reserved
|
||
&valueType,
|
||
(LPBYTE)Value,
|
||
&valueLength
|
||
);
|
||
|
||
if( (err == ERROR_SUCCESS )
|
||
&& (valueType == REG_DWORD )
|
||
&& (valueLength == sizeof(DWORD))) {
|
||
|
||
return 1;
|
||
} else {
|
||
DEBUG_PRINT(SOCKETS, INFO,
|
||
("ReadRegistryDword(%s): err=%d\n", ParameterName, err ));
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* ReadRegistryString
|
||
*
|
||
* Reads a registry value that is stored as a string
|
||
*
|
||
* ENTRY Key - open registry key
|
||
* ParameterName - name of value to read from registry
|
||
* String - pointer to returned string
|
||
* Length - IN: length of String buffer. OUT: length of returned string
|
||
*
|
||
* EXIT String contains string read
|
||
*
|
||
* RETURNS TRUE if success
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
BOOL
|
||
ReadRegistryString(HKEY Key, LPSTR ParameterName, LPSTR String, LPDWORD Length)
|
||
{
|
||
|
||
LONG err;
|
||
DWORD valueType;
|
||
|
||
*String = '\0';
|
||
err = RegQueryValueEx(Key,
|
||
ParameterName,
|
||
NULL, // reserved
|
||
&valueType,
|
||
(LPBYTE)String,
|
||
Length
|
||
);
|
||
|
||
if (err == ERROR_SUCCESS) {
|
||
|
||
DLL_ASSERT(valueType == REG_SZ || valueType == REG_MULTI_SZ);
|
||
|
||
return (*Length) > sizeof(char);
|
||
|
||
} else {
|
||
DEBUG_PRINT(SOCKETS,
|
||
INFO,
|
||
("ReadRegistryString(%s): err=%d\n", ParameterName, err ));
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
UINT
|
||
SockGetSingleValue(
|
||
IN UINT ParameterId,
|
||
OUT LPBYTE Data,
|
||
IN UINT DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieve parameter from Registry/DHCP/TCPIP
|
||
|
||
This is what we look for and where:
|
||
|
||
HostName: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\HostName (Win95)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\Hostname (NT)
|
||
2. (SYSTEM.INI:DNS.HostName)* (N/A)
|
||
3. GetComputerName()
|
||
|
||
DomainName: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\Domain (Win95)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\DhcpDomain (NT)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\Domain (NT)
|
||
2. (SYSTEM.INI:DNS.DomainName)* (N/A)
|
||
3. DHCP (Win95)
|
||
|
||
SearchList: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\SearchList (Win95)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\SearchList (NT)
|
||
2. (SYSTEM.INI:DNS.DNSDomains)* (N/A)
|
||
|
||
NameServer: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\NameServer (Win95)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\DhcpNameServer (NT)
|
||
HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\NameServer (NT)
|
||
2. (SYSTEM.INI:DNS.DNSServers)* (N/A)
|
||
3. DHCP (Win95)
|
||
|
||
* Entries marked thus are registry backups from SYSTEM.INI until all
|
||
keys are moved into registry or if platform is WFW 3.11 (in which
|
||
case there is no registry)
|
||
|
||
ASSUMES 1. Data is big enough to hold the default value (single byte for
|
||
strings, dword for dwords)
|
||
2. Registry is accessible from 16-bit code too
|
||
|
||
Arguments:
|
||
|
||
ParameterId - identifier of parameter to retrieve
|
||
|
||
Data - pointer to untyped storage space for parameter
|
||
|
||
DataLength - length of data returned (in bytes)
|
||
|
||
Return Value:
|
||
|
||
UINT
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_PATH_NOT_FOUND
|
||
can't locate required parameter in registry/ini/etc.
|
||
|
||
--*/
|
||
|
||
{
|
||
UINT error = CheckRegistryForParameter(ParameterId, Data, DataLength);
|
||
|
||
//
|
||
// if the value was not in the registry then we must attempt to get it from
|
||
// another place, specific to the particular variable requested
|
||
//
|
||
|
||
if (error != ERROR_SUCCESS) {
|
||
if (ParameterId == CONFIG_HOSTNAME) {
|
||
|
||
//
|
||
// on Win32 platform we can call GetComputerName() to provide the
|
||
// computer name, which is the default host name, if none is
|
||
// specified elsewhere
|
||
//
|
||
|
||
DWORD length;
|
||
|
||
length = DataLength;
|
||
if (!GetComputerName((LPSTR)Data, &length)) {
|
||
error = GetLastError();
|
||
}
|
||
} else if (ParameterId == CONFIG_DOMAIN) {
|
||
if (GlobalPlatformType == PLATFORM_TYPE_WIN95) {
|
||
error = GetDomainNameFromDhcp(Data, DataLength);
|
||
}
|
||
} else if (ParameterId == CONFIG_NAME_SERVER) {
|
||
if (GlobalPlatformType == PLATFORM_TYPE_WIN95) {
|
||
error = GetDnsServerListFromDhcp(Data, DataLength);
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// the caller is requesting the domain list (or an invalid config
|
||
// parameter value?!?). We have nowhere else to get this value -
|
||
// return an error
|
||
//
|
||
|
||
error = ERROR_PATH_NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
if (error != ERROR_SUCCESS) {
|
||
DLL_PRINT(("SockGetSingleValue(%s) returns %d\r",
|
||
MAP_PARAMETER_ID(ParameterId),
|
||
error
|
||
));
|
||
} else {
|
||
DLL_PRINT(("SockGetSingleValue(%s) returns \"%s\"\n",
|
||
MAP_PARAMETER_ID(ParameterId),
|
||
Data
|
||
));
|
||
}
|
||
}
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
UINT
|
||
CheckRegistryForParameter(
|
||
IN UINT ParameterId,
|
||
OUT LPBYTE Data,
|
||
IN UINT DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieve parameter from registry
|
||
|
||
ASSUMES 1. Data is big enough to hold the default value (single byte for
|
||
strings, dword for dwords)
|
||
|
||
Arguments:
|
||
|
||
ParameterId - identifier of parameter to retrieve
|
||
|
||
Data - pointer to untyped storage space for parameter
|
||
|
||
DataLength - length of data returned (in bytes)
|
||
|
||
Return Value:
|
||
|
||
UINT
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_PATH_NOT_FOUND
|
||
ERROR_INSUFFICIENT_BUFFER
|
||
|
||
--*/
|
||
|
||
{
|
||
HKEY key;
|
||
LONG error = REGOPENKEY(HKEY_LOCAL_MACHINE,
|
||
(GlobalPlatformType == PLATFORM_TYPE_WINNT)
|
||
? "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
||
: "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
|
||
&key
|
||
);
|
||
if (error == ERROR_SUCCESS) {
|
||
|
||
char dhcpBuffer[128]; // arbitrary
|
||
LPSTR p;
|
||
DWORD length;
|
||
DWORD type;
|
||
BOOL tryDhcp;
|
||
|
||
if (GlobalPlatformType == PLATFORM_TYPE_WINNT) {
|
||
FSTRCPY(dhcpBuffer, "Dhcp");
|
||
p = &dhcpBuffer[sizeof("Dhcp") - 1];
|
||
tryDhcp = TRUE;
|
||
} else {
|
||
p = dhcpBuffer;
|
||
tryDhcp = FALSE;
|
||
}
|
||
|
||
FSTRCPY(p, MAP_PARAMETER_ID(ParameterId));
|
||
|
||
//
|
||
// on NT, we look first for the manually-entered variables e.g. "Domain"
|
||
// and if not found, we look a second time for the DHCP-configured
|
||
// variant, e.g. "DhcpDomain"
|
||
//
|
||
|
||
for (int i = 0; i < 2; ++i) {
|
||
|
||
//
|
||
// if NT, first we try the transient key which is written to the
|
||
// registry when we have a dial-up connection
|
||
//
|
||
|
||
if ((i == 0) && (GlobalPlatformType == PLATFORM_TYPE_WINNT)) {
|
||
|
||
HKEY transientKey;
|
||
|
||
error = REGOPENKEY(key, "Transient", &transientKey);
|
||
if (error == ERROR_SUCCESS) {
|
||
length = DataLength;
|
||
error = RegQueryValueEx(transientKey,
|
||
p,
|
||
NULL, // reserved
|
||
&type,
|
||
Data,
|
||
&length
|
||
);
|
||
REGCLOSEKEY(transientKey);
|
||
|
||
//
|
||
// if we succeeded in retrieving a non-empty string then
|
||
// we're done.
|
||
//
|
||
// We test for > 1 because the registry returns the length
|
||
// including the zero-terminator
|
||
//
|
||
|
||
if ((error == ERROR_SUCCESS) && (length > 1)) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
length = DataLength;
|
||
error = RegQueryValueEx(key,
|
||
p,
|
||
NULL, // reserved
|
||
&type,
|
||
Data,
|
||
&length
|
||
);
|
||
|
||
//
|
||
// if the key exists, but there is no value then return an error OR
|
||
// if we didn't find the key (or value) AND NT then try for the DHCP
|
||
// version (Note: We try for DhcpSearchList even though it doesn't
|
||
// exist)
|
||
//
|
||
|
||
if ((error != ERROR_SUCCESS)
|
||
|| (length == 0)
|
||
|| ((length == 1) && (Data[0] == '\0'))) {
|
||
if (tryDhcp) {
|
||
p = dhcpBuffer;
|
||
tryDhcp = FALSE;
|
||
continue;
|
||
} else {
|
||
error = ERROR_PATH_NOT_FOUND;
|
||
break;
|
||
}
|
||
} else if ((UINT)length > DataLength) {
|
||
error = ERROR_INSUFFICIENT_BUFFER;
|
||
break;
|
||
}
|
||
}
|
||
REGCLOSEKEY(key);
|
||
}
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("CheckRegistryForParameter(%s): returning %d\n",
|
||
MAP_PARAMETER_ID(ParameterId),
|
||
error
|
||
));
|
||
}
|
||
|
||
return (UINT)error;
|
||
}
|
||
|
||
|
||
|
||
UINT
|
||
GetDhcpServerFromDhcp(
|
||
IN OUT CAdapterInterface * paiInterface
|
||
)
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* GetDhcpServerFromDhcp
|
||
*
|
||
* Updates an CAdapterInterface with the DHCP server from the DHCP info
|
||
*
|
||
* ENTRY paiInterface - pointer to CAdapterInterface to update
|
||
*
|
||
* EXIT paiInterface - DhcpServer may be updated
|
||
*
|
||
* RETURNS TRUE if AdapterInfo->DhcpServer updated
|
||
*
|
||
* ASSUMES 1. AdapterInfo->Address is valid
|
||
*
|
||
******************************************************************************/
|
||
|
||
{
|
||
LPDHCP_QUERYINFO pDhcpInfoPtr;
|
||
|
||
if ( GlobalPlatformType == PLATFORM_TYPE_WINNT )
|
||
{
|
||
HKEY key;
|
||
|
||
if (paiInterface->GetAdapterName() &&
|
||
OpenAdapterKey(KEY_TCP, paiInterface->GetAdapterName(), &key))
|
||
{
|
||
char dhcpServerAddress[4 * 4];
|
||
DWORD addressLength;
|
||
DWORD fDhcpEnabled = FALSE;
|
||
|
||
ReadRegistryDword(key,
|
||
"EnableDHCP",
|
||
&fDhcpEnabled
|
||
);
|
||
|
||
if ( fDhcpEnabled )
|
||
{
|
||
|
||
addressLength = sizeof(dhcpServerAddress);
|
||
if (ReadRegistryString(key,
|
||
"DhcpServer",
|
||
dhcpServerAddress,
|
||
&addressLength
|
||
))
|
||
{
|
||
DWORD ipAddress = _I_inet_addr(dhcpServerAddress);
|
||
|
||
if ( IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress) )
|
||
{
|
||
paiInterface->AddDhcpServer(ipAddress);
|
||
paiInterface->SetDhcp();
|
||
}
|
||
}
|
||
}
|
||
|
||
//ReadRegistryDword(key,
|
||
// "LeaseObtainedTime",
|
||
// &AdapterInfo->LeaseObtained
|
||
// );
|
||
|
||
//ReadRegistryDword(key,
|
||
// "LeaseTerminatesTime",
|
||
// &AdapterInfo->LeaseExpires
|
||
// );
|
||
|
||
|
||
REGCLOSEKEY(key);
|
||
return fDhcpEnabled;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pDhcpInfoPtr = GetDhcpHardwareInfo()) {
|
||
|
||
DWORD i;
|
||
|
||
for (i = 0; i < pDhcpInfoPtr->NumNICs; ++i)
|
||
{
|
||
LPDHCP_NIC_INFO info;
|
||
register BOOL match;
|
||
|
||
info = &pDhcpInfoPtr->NicInfo[i];
|
||
|
||
match = paiInterface->IsHardwareAddress( ((LPBYTE)pDhcpInfoPtr + info->OffsetHardwareAddress) );
|
||
|
||
if (match && info->DhcpServerAddress) {
|
||
|
||
paiInterface->AddDhcpServer(info->DhcpServerAddress);
|
||
|
||
//
|
||
// side-effect: this adapter is DHCP enabled
|
||
//
|
||
|
||
paiInterface->SetDhcp();
|
||
|
||
DEBUG_PRINT(SOCKETS,
|
||
INFO,
|
||
( "GetDhcpServerFromDhcp %s\n",
|
||
"bugbug"/*inet_ntoa((int)info->DhcpServerAddress)*/ ));
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
} else {
|
||
DEBUG_PRINT(SOCKETS,
|
||
INFO,
|
||
("GetDhcpServerFromDhcp: DhcpInfoPtr is 0\n"));
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
PRIVATE
|
||
UINT
|
||
GetDnsServerListFromDhcp(
|
||
LPBYTE Data,
|
||
UINT DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Attempts to retrieve a list of DNS servers from DHCP if DHCP is active and
|
||
the DNS servers option was specified at the DHCP server
|
||
|
||
Arguments:
|
||
|
||
Data - pointer to place to return the list
|
||
|
||
DataLength - length of Data
|
||
|
||
Return Value:
|
||
|
||
UINT
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure - ERROR_PATH_NOT_FOUND
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDHCP_QUERYINFO pInfo;
|
||
LPBYTE originalData;
|
||
|
||
originalData = Data;
|
||
*Data = 0;
|
||
|
||
if (pInfo = GetDhcpHardwareInfo()) {
|
||
|
||
UINT n = (UINT)pInfo->NumNICs;
|
||
LPDHCP_NIC_INFO pNicInfo = &pInfo->NicInfo[0];
|
||
UINT first = TRUE;
|
||
DWORD smallCache[16];
|
||
UINT cacheIndex = 0;
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): DHCP has %d adapters\n",
|
||
pInfo->NumNICs
|
||
));
|
||
}
|
||
|
||
while (n-- && DataLength) {
|
||
|
||
UINT i;
|
||
LPDWORD pServers = (LPDWORD)((LPBYTE)pInfo + pNicInfo->OffsetDNSServers);
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): NIC %x has %d DNS addresses\n",
|
||
pNicInfo,
|
||
pNicInfo->DNSServersLen / 4
|
||
));
|
||
}
|
||
|
||
for (i = 0; i < pNicInfo->DNSServersLen; i += 4) {
|
||
|
||
IN_ADDR inaddr;
|
||
char* p;
|
||
|
||
//
|
||
// copy the next DNS address from the DHCP list
|
||
//
|
||
|
||
memcpy(&inaddr, pServers++, sizeof(DWORD));
|
||
|
||
//
|
||
// inet_ntoa will validate the address: if it returns NULL, the
|
||
// address is no good, so we skip it
|
||
//
|
||
|
||
p = _I_inet_ntoa(inaddr);
|
||
if ((p != NULL) && *p) {
|
||
|
||
BOOL found;
|
||
UINT cachePos;
|
||
|
||
//
|
||
// now check if we've already seen this address. If we have
|
||
// then we skip it: no sense in adding redundant DNS addresses.
|
||
// This can happen when we have multiple cards, all configured
|
||
// with the same DNS info
|
||
//
|
||
|
||
found = FALSE;
|
||
for (cachePos = 0; cachePos < cacheIndex; ++cachePos) {
|
||
if (smallCache[cachePos] == (DWORD)inaddr.s_addr) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if (!found) {
|
||
|
||
UINT len;
|
||
|
||
//
|
||
// new one: add it
|
||
//
|
||
|
||
if (cacheIndex < (sizeof(smallCache)/sizeof(smallCache[0])) - 1) {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): adding %s to smallCache[%d]\n",
|
||
p,
|
||
cacheIndex
|
||
));
|
||
}
|
||
|
||
smallCache[cacheIndex] = (DWORD)inaddr.s_addr;
|
||
|
||
//
|
||
// increment the cache index; don't let it go past
|
||
// the last element
|
||
//
|
||
|
||
if (cacheIndex < (sizeof(smallCache)/sizeof(smallCache[0])) - 1) {
|
||
++cacheIndex;
|
||
}
|
||
} else {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): smallCache full (!)\n"));
|
||
}
|
||
|
||
}
|
||
|
||
len = FSTRLEN(p);
|
||
|
||
//
|
||
// this assumes that we have more buffer than just
|
||
// enough for one string: if there is only one address
|
||
// and we have been supplied with DataLength == length
|
||
// of the address plus 1 for the zero terminator, then
|
||
// we will fail to copy it since we check for space
|
||
// enough for the string, zero terminator, plus an extra
|
||
// byte for the space separator. But this is being
|
||
// overly pedantic. Casuistry even
|
||
//
|
||
|
||
if (DataLength > len + 1) {
|
||
if (!first) {
|
||
*Data++ = ' ';
|
||
--DataLength;
|
||
}
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp() found \"%s\"\n",
|
||
p
|
||
));
|
||
}
|
||
|
||
FSTRCPY(Data, p);
|
||
DataLength -= len;
|
||
Data += len;
|
||
first = FALSE;
|
||
} else {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): out of buffer space (need=%d, left=%d)\n",
|
||
len + 1,
|
||
DataLength
|
||
));
|
||
}
|
||
|
||
}
|
||
} else {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp(): already seen address %s\n",
|
||
p
|
||
));
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
++pNicInfo;
|
||
}
|
||
DllFreeMem((void*)pInfo);
|
||
|
||
//
|
||
// if we didn't find any DNS addresses or couldn't fit them in the
|
||
// supplied buffer then return an error
|
||
//
|
||
|
||
return (UINT)((*originalData != 0) ? ERROR_SUCCESS : ERROR_PATH_NOT_FOUND);
|
||
} else {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDnsServerListFromDhcp() returning %d\n",
|
||
ERROR_PATH_NOT_FOUND
|
||
));
|
||
}
|
||
|
||
return ERROR_PATH_NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
UINT
|
||
GetDomainNameFromDhcp(
|
||
LPBYTE Data,
|
||
UINT DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Attempts to retrieve the domain from DHCP. In this case, the DHCP server
|
||
gave out the domain name we are supposed to use
|
||
|
||
Arguments:
|
||
|
||
Data - pointer to place to return the list
|
||
|
||
DataLength - length of Data
|
||
|
||
Return Value:
|
||
|
||
UINT
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDHCP_QUERYINFO pInfo;
|
||
|
||
pInfo = GetDhcpHardwareInfo();
|
||
if (pInfo) {
|
||
|
||
UINT n;
|
||
LPDHCP_NIC_INFO pNicInfo;
|
||
|
||
//
|
||
// search for the first domain name in the NIC list
|
||
//
|
||
|
||
n = (UINT)pInfo->NumNICs;
|
||
pNicInfo = &pInfo->NicInfo[0];
|
||
|
||
//
|
||
// BUGBUG - is this correct for multi-homed hosts?
|
||
//
|
||
|
||
while (n--) {
|
||
|
||
DWORD dnLen;
|
||
|
||
dnLen = pNicInfo->DomainNameLen;
|
||
if (dnLen && (DataLength >= dnLen)) {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDomainNameFromDhcp() found \"%s\"\n",
|
||
(LPBYTE)pInfo + pNicInfo->OffsetDomainName
|
||
));
|
||
}
|
||
|
||
memcpy(Data,
|
||
(LPBYTE)pInfo + pNicInfo->OffsetDomainName,
|
||
(size_t)dnLen
|
||
);
|
||
|
||
//
|
||
// we've got our one and only domain name (that we're interested
|
||
// in, anyway), so exit
|
||
//
|
||
|
||
break;
|
||
}
|
||
}
|
||
DllFreeMem((void*)pInfo);
|
||
return ERROR_SUCCESS;
|
||
} else {
|
||
|
||
IF_DEBUG(REGISTRY) {
|
||
DLL_PRINT(("GetDomainNameFromDhcp() returning %d\n",
|
||
ERROR_PATH_NOT_FOUND
|
||
));
|
||
}
|
||
|
||
return ERROR_PATH_NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* GetDhcpHardwareInfo
|
||
*
|
||
* Retrieves all the hardware-specific information for all adapters from the
|
||
* DHCP VxD
|
||
*
|
||
* ENTRY nothing
|
||
*
|
||
* EXIT nothing
|
||
*
|
||
* RETURNS Success - pointer to allocated buffer containing all hardware info
|
||
* Failure - NULL
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
PRIVATE
|
||
LPDHCP_QUERYINFO
|
||
GetDhcpHardwareInfo(
|
||
VOID
|
||
)
|
||
{
|
||
LPDHCP_QUERYINFO info = NULL;
|
||
DWORD_PTR handle = OpenDhcpVxdHandle();
|
||
|
||
if (handle) {
|
||
|
||
WORD result;
|
||
DWORD sizeRequired;
|
||
|
||
result = DhcpVxdRequest(handle,
|
||
DHCP_QUERY_INFO,
|
||
sizeof(sizeRequired),
|
||
&sizeRequired
|
||
);
|
||
|
||
//
|
||
// ERROR_BUFFER_OVERFLOW tells us exactly how many bytes we need. If we
|
||
// don't get this error back, then its an unexpected (i.e. error)
|
||
// situation
|
||
//
|
||
|
||
if (result == ERROR_BUFFER_OVERFLOW) {
|
||
info = (LPDHCP_QUERYINFO)DllAllocMem((size_t)sizeRequired);
|
||
if (info) {
|
||
result = DhcpVxdRequest(handle,
|
||
DHCP_QUERY_INFO,
|
||
(WORD)sizeRequired,
|
||
info
|
||
);
|
||
if (result != ERROR_SUCCESS) {
|
||
DllFreeMem((void*)info);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (handle) {
|
||
OsCloseVxdHandle(handle);
|
||
}
|
||
return info;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* OpenDhcpVxdHandle
|
||
*
|
||
* On Snowball, just retrieves the (real-mode) entry point address to the VxD
|
||
*
|
||
* ENTRY nothing
|
||
*
|
||
* EXIT DhcpVxdEntryPoint set
|
||
*
|
||
* RETURNS DhcpVxdEntryPoint
|
||
*
|
||
* ASSUMES 1. We are running in V86 mode
|
||
*
|
||
******************************************************************************/
|
||
|
||
PRIVATE
|
||
DWORD_PTR
|
||
OpenDhcpVxdHandle(
|
||
VOID
|
||
)
|
||
{
|
||
return OsOpenVxdHandle("VDHCP", VDHCP_Device_ID);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* DhcpVxdRequest
|
||
*
|
||
* Makes a DHCP VxD request - passes a function code, parameter buffer and
|
||
* length to the (real-mode/V86) VxD entry-point
|
||
*
|
||
* ENTRY Handle - handle for Win32 call
|
||
* Request - DHCP VxD request
|
||
* BufferLength - length of Buffer
|
||
* Buffer - pointer to request-specific parameters
|
||
*
|
||
* EXIT depends on request
|
||
*
|
||
* RETURNS Success - 0
|
||
* Failure - ERROR_PATH_NOT_FOUND
|
||
* Returned if a specified adapter address could not be
|
||
* found
|
||
*
|
||
* ERROR_BUFFER_OVERFLOW
|
||
* Returned if the supplied buffer is too small to contain
|
||
* the requested information
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
PRIVATE
|
||
WORD
|
||
DhcpVxdRequest(
|
||
IN DWORD_PTR Handle,
|
||
IN WORD Request,
|
||
IN WORD BufferLength,
|
||
OUT LPVOID Buffer
|
||
)
|
||
{
|
||
return (WORD) OsSubmitVxdRequest(Handle,
|
||
(INT)Request,
|
||
(LPVOID)Buffer,
|
||
(INT)BufferLength
|
||
);
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
DWORD_PTR
|
||
OsOpenVxdHandle(
|
||
CHAR * VxdName,
|
||
WORD VxdId
|
||
)
|
||
{
|
||
HANDLE VxdHandle;
|
||
CHAR VxdPath[MAX_PATH];
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DLL_ASSERT( VxdName != NULL );
|
||
DLL_ASSERT( VxdId != 0 );
|
||
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsOpenVxdHandle: id = %04X, name = %s\n",
|
||
VxdId,
|
||
VxdName ));
|
||
}
|
||
|
||
//
|
||
// Build the VxD path.
|
||
//
|
||
|
||
FSTRCPY( VxdPath, "\\\\.\\");
|
||
if(FSTRLEN(VxdPath) + FSTRLEN(VxdName) >= sizeof(VxdPath) / sizeof(VxdPath[0]))
|
||
{
|
||
DLL_ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
|
||
FSTRCAT( VxdPath, VxdName);
|
||
|
||
//
|
||
// Open the device.
|
||
//
|
||
// First try the name without the .VXD extension. This will
|
||
// cause CreateFile to connect with the VxD if it is already
|
||
// loaded (CreateFile will not load the VxD in this case).
|
||
//
|
||
|
||
VxdHandle = CreateFile( VxdPath,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_FLAG_DELETE_ON_CLOSE,
|
||
NULL );
|
||
|
||
if( VxdHandle == INVALID_HANDLE_VALUE )
|
||
{
|
||
//
|
||
// Not found. Append the .VXD extension and try again.
|
||
// This will cause CreateFile to load the VxD.
|
||
//
|
||
|
||
FSTRCAT( VxdPath, ".VXD" );
|
||
VxdHandle = CreateFile( VxdPath,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_FLAG_DELETE_ON_CLOSE,
|
||
NULL );
|
||
}
|
||
|
||
if( VxdHandle != INVALID_HANDLE_VALUE )
|
||
{
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsOpenVxdHandle: returning handle %08lX\n",
|
||
VxdHandle ));
|
||
}
|
||
|
||
return (DWORD_PTR)VxdHandle;
|
||
}
|
||
|
||
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsOpenVxdHandle: cannot open %s (%04X), error %d\n",
|
||
VxdPath,
|
||
VxdId,
|
||
GetLastError() ));
|
||
}
|
||
|
||
return 0;
|
||
|
||
} // OsOpenVxdHandle
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
OsCloseVxdHandle(
|
||
DWORD_PTR VxdHandle
|
||
)
|
||
{
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DLL_ASSERT( VxdHandle != 0 );
|
||
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsCloseVxdHandle: handle %08X\n",
|
||
VxdHandle ));
|
||
}
|
||
|
||
if( !CloseHandle( (HANDLE)VxdHandle ) )
|
||
{
|
||
DLL_PRINT(( "OsCloseVxdHandle: cannot close handle %08X, error %d\n",
|
||
VxdHandle,
|
||
GetLastError() ));
|
||
}
|
||
|
||
} // OsCloseVxdHandle
|
||
|
||
|
||
PRIVATE
|
||
INT
|
||
OsSubmitVxdRequest(
|
||
DWORD_PTR VxdHandle,
|
||
INT OpCode,
|
||
LPVOID Param,
|
||
INT ParamLength
|
||
)
|
||
{
|
||
DWORD BytesRead;
|
||
INT Result = 0;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DLL_ASSERT( VxdHandle != 0 );
|
||
DLL_ASSERT( ( Param != NULL ) || ( ParamLength == 0 ) );
|
||
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsSubmitVxdRequest: opcode %04X, param %08lX, length %d\n",
|
||
OpCode,
|
||
Param,
|
||
ParamLength ));
|
||
}
|
||
|
||
if( !DeviceIoControl( (HANDLE)VxdHandle,
|
||
OpCode,
|
||
Param,
|
||
ParamLength,
|
||
Param,
|
||
ParamLength,
|
||
&BytesRead,
|
||
NULL ) )
|
||
{
|
||
Result = GetLastError();
|
||
}
|
||
|
||
IF_DEBUG( VXD_IO )
|
||
{
|
||
DLL_PRINT(( "OsSubmitVxdRequest: returning %d\n",
|
||
Result ));
|
||
}
|
||
|
||
return Result;
|
||
|
||
} // OsSubmitVxdRequest
|