mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2419 lines
54 KiB
2419 lines
54 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rnr2ops.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for the DNS RnR2 provider
|
|
|
|
Author:
|
|
|
|
Arnold Miller (ArnoldM) 3-Jan-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// Bit defs for the protocols
|
|
//
|
|
|
|
#define UDP_BIT 1
|
|
#define TCP_BIT 2
|
|
|
|
|
|
typedef struct _DNS_RNR_CONTEXT
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
LONG lSig;
|
|
LONG lInUse;
|
|
LONG lInstance; // counter to tell if we've
|
|
// resolved this yet
|
|
DWORD fFlags; // always nice to have
|
|
DWORD dwControlFlags;
|
|
DWORD dwUdpPort;
|
|
DWORD dwTcpPort;
|
|
DWORD dwNameSpace;
|
|
HANDLE Handle; // the corresponding RnR handle
|
|
DWORD nProt;
|
|
GUID gdType; // the type we are seeking
|
|
GUID gdProviderId; // the provider being used
|
|
DWORD dwHostSize;
|
|
struct hostent * phent;
|
|
PHOOKER_INFORMATION HookerInfo;
|
|
WCHAR wcName[1]; // the name
|
|
} DNS_RNR_CONTEXT, *PDNS_RNR_CONTEXT;
|
|
|
|
#define RNR_SIG 0xaabbccdd
|
|
|
|
#define REVERSELOOK 0x2
|
|
#define LOCALLOOK 0x4
|
|
#define NEEDDOMAIN 0x8
|
|
#define IANALOOK 0x10
|
|
#define LOOPLOOK 0x20
|
|
|
|
#define DNSGUID {0x22059d40, \
|
|
0x7e9e, \
|
|
0x11cf, \
|
|
0xae, \
|
|
0x5a, \
|
|
0x00, \
|
|
0xaa, \
|
|
0x00, \
|
|
0xa7, \
|
|
0x11, \
|
|
0x2b}
|
|
|
|
//
|
|
// Function prototypes
|
|
//
|
|
|
|
struct servent *
|
|
CopyServEntry(
|
|
struct servent * phent,
|
|
PBYTE pbAllocated,
|
|
LONG lSizeOf,
|
|
PLONG plTaken,
|
|
BOOL fOffsets
|
|
);
|
|
|
|
struct hostent *
|
|
CopyHostEntry(
|
|
struct hostent * phent,
|
|
PBYTE pbAllocated,
|
|
LONG lSizeOf,
|
|
PLONG plTaken,
|
|
BOOL fOffsets
|
|
);
|
|
|
|
PDNS_RNR_CONTEXT
|
|
RnR2GetContext(
|
|
HANDLE hContext
|
|
);
|
|
|
|
PDNS_RNR_CONTEXT
|
|
RnR2MakeContext(
|
|
IN HANDLE hContext,
|
|
IN DWORD dwExtra
|
|
);
|
|
|
|
BOOL
|
|
IsLocalComputerName(
|
|
IN LPGUID ProviderId,
|
|
IN LPSTR AnsiName
|
|
);
|
|
|
|
VOID
|
|
RnR2Cleanup(
|
|
VOID
|
|
);
|
|
|
|
LPSTR
|
|
GetAnsiNameRnR (
|
|
IN PWCHAR Name,
|
|
IN LPSTR Domain
|
|
);
|
|
|
|
DWORD
|
|
FetchPortFromClassInfo(
|
|
IN DWORD dwType,
|
|
IN LPGUID lpType,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
);
|
|
|
|
VOID
|
|
RnR2ReleaseContext(
|
|
IN PDNS_RNR_CONTEXT pdrc
|
|
);
|
|
|
|
DWORD
|
|
PackCsAddr (
|
|
IN PHOSTENT HostEntry,
|
|
IN DWORD UdpPort,
|
|
IN DWORD TcpPort,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT PLONG lplBufferLength,
|
|
OUT LPDWORD lpdwBytesTaken,
|
|
IN OUT LPDWORD Count,
|
|
BOOL fReversi
|
|
);
|
|
|
|
DWORD
|
|
AllocateUnicodeString (
|
|
IN LPSTR lpAnsi,
|
|
IN OUT PWCHAR *lppUnicode
|
|
);
|
|
|
|
DWORD
|
|
GetServerAndProtocolsFromString(
|
|
PHOOKER_INFORMATION HookerInfo,
|
|
PWCHAR lpszString,
|
|
LPGUID lpType,
|
|
struct servent ** pServEnt
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceBegin(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSAQUERYSETW lpqsRestrictions,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
|
|
IN DWORD dwControlFlags,
|
|
OUT LPHANDLE lphLookup
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceNext(
|
|
IN HANDLE hLookup,
|
|
IN DWORD dwControlFlags,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
OUT LPWSAQUERYSETW lpqsResults
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPUnInstallNameSpace(
|
|
IN LPGUID lpProviderId
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPCleanup(
|
|
IN LPGUID lpProviderId
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceEnd(
|
|
IN HANDLE hLookup
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPSetService(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
|
|
IN LPWSAQUERYSETW lpqsRegInfo,
|
|
IN WSAESETSERVICEOP essOperation,
|
|
IN DWORD dwControlFlags
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPInstallServiceClass(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPRemoveServiceClass(
|
|
IN LPGUID lpProviderId,
|
|
IN LPGUID lpServiceCallId
|
|
);
|
|
|
|
INT WINAPI
|
|
NSPGetServiceClassInfo(
|
|
IN LPGUID lpProviderId,
|
|
IN OUT LPDWORD lpdwBufSize,
|
|
IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
);
|
|
|
|
|
|
#define GuidEqual(x,y) (!memcmp( (PVOID)(x), (PVOID)(y), sizeof(GUID) ))
|
|
|
|
|
|
// Definitions and data
|
|
//
|
|
|
|
LIST_ENTRY ListAnchor = {&ListAnchor, &ListAnchor};
|
|
#define CHECKANCHORQUEUE // do queue checking on the above
|
|
|
|
GUID HostnameGuid = SVCID_HOSTNAME;
|
|
GUID AddressGuid = SVCID_INET_HOSTADDRBYINETSTRING;
|
|
GUID InetHostName = SVCID_INET_HOSTADDRBYNAME;
|
|
GUID IANAGuid = SVCID_INET_SERVICEBYNAME;
|
|
|
|
LONG lStartupCount;
|
|
|
|
#define NAME_SIZE 50
|
|
|
|
#define NOPORTDEFINED (0xffffffff)
|
|
|
|
#define UDP_PORT 0 // look for the UDP port type
|
|
#define TCP_PORT 1 // look for the TCP port type
|
|
|
|
CRITICAL_SECTION csRnRLock;
|
|
|
|
NSP_ROUTINE nsrVector = {
|
|
sizeof(NSP_ROUTINE),
|
|
1, // major version
|
|
1, // minor version
|
|
NSPCleanup,
|
|
NSPLookupServiceBegin,
|
|
NSPLookupServiceNext,
|
|
NSPLookupServiceEnd,
|
|
NSPSetService,
|
|
NSPInstallServiceClass,
|
|
NSPRemoveServiceClass,
|
|
NSPGetServiceClassInfo
|
|
};
|
|
|
|
//
|
|
// Function Bodies
|
|
//
|
|
|
|
|
|
//
|
|
// Get a servent for a string.
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
GetServerAndProtocolsFromString(
|
|
PHOOKER_INFORMATION HookerInfo,
|
|
PWCHAR lpszString,
|
|
LPGUID lpType,
|
|
struct servent ** pServEnt
|
|
)
|
|
{
|
|
DWORD nProt;
|
|
struct servent * sent;
|
|
|
|
if(lpszString
|
|
&&
|
|
lpType
|
|
&&
|
|
(GuidEqual(lpType, &HostnameGuid)
|
|
||
|
|
GuidEqual(lpType, &InetHostName) ) )
|
|
{
|
|
PCHAR servname, protocolname;
|
|
WCHAR wszTemp[1000];
|
|
INT port = 0;
|
|
WCHAR * pwszTemp;
|
|
DWORD dwLen;
|
|
PCHAR pszTemp;
|
|
|
|
//
|
|
// the string is of the form service/protocol. If there is no
|
|
// protocol, just look up the name and take the first entry.
|
|
// The service name might be a port number ...
|
|
//
|
|
|
|
pwszTemp = wcschr(lpszString, L'/');
|
|
if(!pwszTemp)
|
|
{
|
|
pwszTemp = wcschr(lpszString, L'\0');
|
|
}
|
|
|
|
//
|
|
// copy the service name so we can render it into ASCII
|
|
//
|
|
|
|
dwLen = (pwszTemp - lpszString);
|
|
memcpy(wszTemp, lpszString, dwLen * sizeof(WCHAR));
|
|
wszTemp[dwLen] = 0;
|
|
servname = GetAnsiNameRnR(wszTemp, 0);
|
|
|
|
//
|
|
// if it's numeric, then we get a port from it.
|
|
//
|
|
|
|
for(pszTemp = servname;
|
|
*pszTemp && isdigit(*pszTemp);
|
|
pszTemp++) ;
|
|
|
|
if(!*pszTemp)
|
|
{
|
|
//
|
|
// it's numeric. Get the number
|
|
//
|
|
|
|
port = atoi(servname);
|
|
}
|
|
|
|
|
|
//
|
|
// now the protocol.
|
|
//
|
|
|
|
if(!*pwszTemp
|
|
||
|
|
!*++pwszTemp)
|
|
{
|
|
protocolname = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
protocolname = GetAnsiNameRnR(pwszTemp, 0);
|
|
|
|
}
|
|
//
|
|
// let's get the entry
|
|
//
|
|
|
|
SockPreApiCallout();
|
|
|
|
if(port)
|
|
{
|
|
sent = HookerInfo->getservbyport(port, protocolname);
|
|
}
|
|
else
|
|
{
|
|
sent = HookerInfo->getservbyname(servname, protocolname);
|
|
}
|
|
|
|
SockPostApiCallout();
|
|
|
|
if(servname)
|
|
{
|
|
SOCK_FREE_HEAP(servname);
|
|
}
|
|
|
|
if(protocolname)
|
|
{
|
|
SOCK_FREE_HEAP(protocolname);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sent = 0;
|
|
}
|
|
|
|
if(pServEnt)
|
|
{
|
|
*pServEnt = sent;
|
|
}
|
|
if(sent)
|
|
{
|
|
if(_stricmp("udp", sent->s_proto))
|
|
{
|
|
nProt = UDP_BIT;
|
|
}
|
|
else
|
|
{
|
|
nProt = TCP_BIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nProt = UDP_BIT | TCP_BIT;
|
|
}
|
|
return(nProt);
|
|
}
|
|
|
|
|
|
DWORD
|
|
PackCsAddr (
|
|
IN PHOSTENT HostEntry,
|
|
IN DWORD UdpPort,
|
|
IN DWORD TcpPort,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT PLONG lplBufferLength,
|
|
OUT LPDWORD lpdwBytesTaken,
|
|
IN OUT LPDWORD Count,
|
|
BOOL fReversi
|
|
)
|
|
{
|
|
DWORD count, nAddresses;
|
|
DWORD i;
|
|
DWORD requiredBufferLength;
|
|
PSOCKADDR_IN sockaddrIn;
|
|
PCSADDR_INFO csaddrInfo;
|
|
|
|
//
|
|
// figure out how many addresse types we have to return
|
|
//
|
|
|
|
nAddresses = 0;
|
|
if(UdpPort != NOPORTDEFINED)
|
|
{
|
|
nAddresses++;
|
|
}
|
|
if(TcpPort != NOPORTDEFINED)
|
|
{
|
|
nAddresses++;
|
|
}
|
|
|
|
//
|
|
// Count the number of IP addresses in the hostent.
|
|
//
|
|
|
|
for ( count = 0; HostEntry->h_addr_list[count] != NULL; count++ );
|
|
|
|
count *= nAddresses;
|
|
|
|
//
|
|
// Make sure that the buffer is large enough to hold all the entries
|
|
// which will be necessary.
|
|
//
|
|
|
|
requiredBufferLength = count * (sizeof(CSADDR_INFO) +
|
|
2*sizeof(SOCKADDR_IN));
|
|
;
|
|
|
|
*lplBufferLength -= requiredBufferLength;
|
|
*lpdwBytesTaken = requiredBufferLength;
|
|
if ( *lplBufferLength < 0)
|
|
{
|
|
return(WSAEFAULT);
|
|
}
|
|
|
|
|
|
//
|
|
// For each IP address, fill in the user buffer with one entry.
|
|
//
|
|
|
|
sockaddrIn = (PSOCKADDR_IN)((PCSADDR_INFO)lpCsaddrBuffer + count);
|
|
csaddrInfo = lpCsaddrBuffer;
|
|
|
|
while(nAddresses--)
|
|
{
|
|
BOOL IsTcp;
|
|
WORD Port;
|
|
|
|
if(UdpPort != NOPORTDEFINED)
|
|
{
|
|
Port = (WORD)UdpPort;
|
|
IsTcp = TRUE;
|
|
UdpPort = 0;
|
|
}
|
|
else if(TcpPort != NOPORTDEFINED)
|
|
{
|
|
Port = (WORD)TcpPort;
|
|
IsTcp = FALSE;
|
|
TcpPort = 0;
|
|
}
|
|
|
|
for ( i = 0; i < count; i++, csaddrInfo++, sockaddrIn++ )
|
|
{
|
|
|
|
//
|
|
// First fill in the local address. It should remain basically
|
|
// all zeros except for the family so that it is a "wildcard"
|
|
// address for binding.
|
|
//
|
|
|
|
RtlZeroMemory( csaddrInfo, sizeof(*csaddrInfo) );
|
|
|
|
csaddrInfo->LocalAddr.lpSockaddr = (LPSOCKADDR)sockaddrIn;
|
|
csaddrInfo->LocalAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
|
|
//
|
|
// Now the remote address.
|
|
//
|
|
|
|
sockaddrIn++;
|
|
|
|
csaddrInfo->RemoteAddr.lpSockaddr = (PSOCKADDR)( sockaddrIn );
|
|
csaddrInfo->RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
sockaddrIn = (PSOCKADDR_IN)csaddrInfo->RemoteAddr.lpSockaddr;
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
|
|
//
|
|
// Fill in the remote address with the actual address, both port
|
|
// and IP address.
|
|
//
|
|
|
|
sockaddrIn->sin_port = htons(Port);
|
|
sockaddrIn->sin_addr.s_addr =
|
|
*((long *)(HostEntry->h_addr_list[i]));
|
|
|
|
//
|
|
// Lastly, fill in the protocol information.
|
|
//
|
|
|
|
if ( IsTcp ) {
|
|
csaddrInfo->iSocketType = SOCK_STREAM;
|
|
csaddrInfo->iProtocol = IPPROTO_TCP;
|
|
} else {
|
|
csaddrInfo->iSocketType = SOCK_DGRAM;
|
|
csaddrInfo->iProtocol = IPPROTO_UDP;
|
|
}
|
|
if(fReversi)
|
|
{
|
|
PSOCKADDR temp = csaddrInfo->RemoteAddr.lpSockaddr;
|
|
|
|
csaddrInfo->RemoteAddr.lpSockaddr =
|
|
csaddrInfo->LocalAddr.lpSockaddr;
|
|
|
|
csaddrInfo->LocalAddr.lpSockaddr = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
*Count = count;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
PVOID
|
|
AllocLocal(
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
PVOID pvMem;
|
|
|
|
pvMem = SOCK_ALLOCATE_HEAP(dwSize);
|
|
if(pvMem)
|
|
{
|
|
RtlZeroMemory(pvMem, dwSize);
|
|
}
|
|
return(pvMem);
|
|
}
|
|
|
|
LPSTR
|
|
GetAnsiNameRnR (
|
|
IN PWCHAR Name,
|
|
IN LPSTR Domain
|
|
)
|
|
{
|
|
|
|
PCHAR pszBuffer;
|
|
DWORD dwLen;
|
|
WORD wLen;
|
|
|
|
if(Domain)
|
|
{
|
|
wLen = (WORD)strlen(Domain);
|
|
}
|
|
else
|
|
{
|
|
wLen = 0;
|
|
}
|
|
dwLen = ((wcslen(Name) + 1) * sizeof(WCHAR) * 2) + wLen;
|
|
pszBuffer = SOCK_ALLOCATE_HEAP(dwLen);
|
|
if ( pszBuffer == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
if(!WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
Name,
|
|
-1,
|
|
pszBuffer,
|
|
dwLen,
|
|
0,
|
|
0))
|
|
{
|
|
SOCK_FREE_HEAP( pszBuffer );
|
|
return NULL;
|
|
}
|
|
|
|
if(Domain)
|
|
{
|
|
strcat(pszBuffer, Domain);
|
|
}
|
|
return(pszBuffer);
|
|
}
|
|
|
|
|
|
PDNS_RNR_CONTEXT
|
|
RnR2MakeContext(
|
|
IN HANDLE hHandle,
|
|
IN DWORD dwExtra
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Allocate memory for a context, and enqueue it on the list
|
|
--*/
|
|
{
|
|
PDNS_RNR_CONTEXT pdrc;
|
|
|
|
pdrc = (PDNS_RNR_CONTEXT)AllocLocal(
|
|
sizeof(DNS_RNR_CONTEXT) +
|
|
dwExtra);
|
|
if(pdrc)
|
|
{
|
|
pdrc->lInUse = 2;
|
|
pdrc->Handle = (hHandle ? hHandle : (HANDLE)pdrc);
|
|
pdrc->lSig = RNR_SIG;
|
|
pdrc->lInstance = -1;
|
|
EnterCriticalSection(&csRnRLock);
|
|
InsertHeadList(&ListAnchor, &pdrc->ListEntry);
|
|
LeaveCriticalSection(&csRnRLock);
|
|
}
|
|
return(pdrc);
|
|
}
|
|
|
|
VOID
|
|
RnR2Cleanup()
|
|
{
|
|
PLIST_ENTRY pdrc;
|
|
|
|
EnterCriticalSection(&csRnRLock);
|
|
|
|
while((pdrc = ListAnchor.Flink) != &ListAnchor)
|
|
{
|
|
RnR2ReleaseContext((PDNS_RNR_CONTEXT)pdrc);
|
|
}
|
|
|
|
LeaveCriticalSection(&csRnRLock);
|
|
DeleteCriticalSection(&csRnRLock);
|
|
}
|
|
|
|
VOID
|
|
RnR2ReleaseContext(
|
|
IN PDNS_RNR_CONTEXT pdrc
|
|
)
|
|
{
|
|
/*++
|
|
Routine Description:
|
|
|
|
Dereference an RNR Context and free it if it is no longer referenced.
|
|
|
|
--*/
|
|
|
|
EnterCriticalSection(&csRnRLock);
|
|
if(--pdrc->lInUse == 0)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
|
|
//
|
|
// remove from queue
|
|
//
|
|
|
|
#ifdef CHECKANCHORQUEUE
|
|
|
|
for(Entry = ListAnchor.Flink;
|
|
Entry != &ListAnchor;
|
|
Entry = Entry->Flink)
|
|
{
|
|
if((PDNS_RNR_CONTEXT)Entry == pdrc)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
SOCK_ASSERT(Entry != &ListAnchor);
|
|
#endif
|
|
RemoveEntryList(&pdrc->ListEntry);
|
|
if(pdrc->phent)
|
|
{
|
|
SOCK_FREE_HEAP(pdrc->phent);
|
|
}
|
|
|
|
if( pdrc->HookerInfo ) {
|
|
SockDereferenceHooker( pdrc->HookerInfo );
|
|
}
|
|
|
|
SOCK_FREE_HEAP(pdrc);
|
|
}
|
|
LeaveCriticalSection(&csRnRLock);
|
|
}
|
|
|
|
PDNS_RNR_CONTEXT
|
|
RnR2GetContext(
|
|
IN HANDLE Handle
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks the existing DNS contexts to see if we have one
|
|
for this call.
|
|
|
|
Arguments:
|
|
|
|
Handle - the RnR handle
|
|
|
|
--*/
|
|
PDNS_RNR_CONTEXT pdrc = 0;
|
|
PLIST_ENTRY Entry;
|
|
|
|
EnterCriticalSection(&csRnRLock);
|
|
|
|
for(Entry = ListAnchor.Flink;
|
|
Entry != &ListAnchor;
|
|
Entry = Entry->Flink)
|
|
{
|
|
PDNS_RNR_CONTEXT pdrc1;
|
|
|
|
pdrc1 = (PDNS_RNR_CONTEXT)Entry;
|
|
if(pdrc1 == (PDNS_RNR_CONTEXT)Handle)
|
|
{
|
|
pdrc = pdrc1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pdrc)
|
|
{
|
|
++pdrc->lInUse;
|
|
}
|
|
LeaveCriticalSection(&csRnRLock);
|
|
return(pdrc);
|
|
}
|
|
|
|
DWORD
|
|
TryFetchClass(
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
|
|
IN PWCHAR pwszMatch)
|
|
{
|
|
/*++
|
|
Routine Description:
|
|
Helper routine to rummage through the Class Info entries looking
|
|
for the desired one. If none is found, return NOPORTDEFINED. If
|
|
one is found, return the value as a port number.
|
|
--*/
|
|
if(lpServiceClassInfo)
|
|
{
|
|
DWORD dwNumClassInfos = lpServiceClassInfo->dwCount;
|
|
LPWSANSCLASSINFOW lpClassInfoBuf = lpServiceClassInfo->lpClassInfos;
|
|
|
|
for(; dwNumClassInfos; dwNumClassInfos--, lpClassInfoBuf++)
|
|
{
|
|
if(!_wcsicmp(pwszMatch, lpClassInfoBuf->lpszName)
|
|
&&
|
|
(lpClassInfoBuf->dwValueType == REG_DWORD)
|
|
&&
|
|
(lpClassInfoBuf->dwValueSize >= sizeof(WORD)) )
|
|
{
|
|
return(*(PWORD)lpClassInfoBuf->lpValue);
|
|
}
|
|
}
|
|
}
|
|
return(NOPORTDEFINED);
|
|
}
|
|
|
|
DWORD
|
|
FetchPortFromClassInfo(
|
|
IN DWORD dwType,
|
|
IN LPGUID lpType,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Find the port number corresponding to the connection type.
|
|
--*/
|
|
{
|
|
DWORD dwPort;
|
|
|
|
switch(dwType)
|
|
{
|
|
case UDP_PORT:
|
|
|
|
if(IS_SVCID_UDP( lpType))
|
|
{
|
|
dwPort = PORT_FROM_SVCID_UDP(lpType);
|
|
}
|
|
else
|
|
{
|
|
dwPort = TryFetchClass(
|
|
lpServiceClassInfo,
|
|
SERVICE_TYPE_VALUE_UDPPORTW);
|
|
}
|
|
break;
|
|
|
|
case TCP_PORT:
|
|
|
|
if(IS_SVCID_TCP( lpType))
|
|
{
|
|
dwPort = PORT_FROM_SVCID_TCP(lpType);
|
|
}
|
|
else
|
|
{
|
|
dwPort = TryFetchClass(
|
|
lpServiceClassInfo,
|
|
SERVICE_TYPE_VALUE_TCPPORTW);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
dwPort = NOPORTDEFINED;
|
|
}
|
|
return(dwPort);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceBegin(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSAQUERYSETW lpqsRestrictions,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
|
|
IN DWORD dwControlFlags,
|
|
OUT LPHANDLE lphLookup
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This is the RnR routine that begins a lookup.
|
|
--*/
|
|
{
|
|
PDNS_RNR_CONTEXT pdrc;
|
|
BOOL fNameLook;
|
|
DWORD nProt;
|
|
DWORD dwTcpPort, dwUdpPort;
|
|
DWORD dwHostLen;
|
|
DWORD dwLocalFlags = 0;
|
|
WCHAR * pwszServiceName = lpqsRestrictions->lpszServiceInstanceName;
|
|
WCHAR wszString[1000];
|
|
PHOOKER_INFORMATION hookerInfo;
|
|
struct servent * sent;
|
|
INT err;
|
|
|
|
SOCK_ENTER( "NSPLookupServiceBegin", lpProviderId, lpqsRestrictions, lpServiceClassInfo, (PVOID)dwControlFlags );
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
if( lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW) ) {
|
|
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( WSAEFAULT );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
if( !lpqsRestrictions->lpServiceClassId ) {
|
|
|
|
//
|
|
// gotta have a class ID.
|
|
//
|
|
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( WSA_INVALID_PARAMETER );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Check that no context is specified.
|
|
//
|
|
if((lpqsRestrictions->lpszContext
|
|
&&
|
|
(lpqsRestrictions->lpszContext[0] != 0)
|
|
&&
|
|
wcscmp(&lpqsRestrictions->lpszContext[0], L"\\") )
|
|
||
|
|
(dwControlFlags & LUP_CONTAINERS) )
|
|
|
|
{
|
|
//
|
|
// if not the default context or need containers, can't handle it
|
|
//
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( WSANO_DATA );
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
//
|
|
// Try to find our hooker.
|
|
//
|
|
|
|
hookerInfo = SockFindAndReferenceHooker(
|
|
lpProviderId
|
|
);
|
|
|
|
if( hookerInfo == NULL ) {
|
|
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( WSA_INVALID_PARAMETER );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// If this is a lookup of the local name
|
|
// allow the instance
|
|
// name to be NULL. If it is a reverse lookup, mark it as such.
|
|
// If it is a host lookup, check for one of the several special
|
|
// names that require returning specific local information.
|
|
//
|
|
|
|
if( GuidEqual(lpqsRestrictions->lpServiceClassId, &AddressGuid) )
|
|
{
|
|
dwLocalFlags |= REVERSELOOK;
|
|
}
|
|
else if(GuidEqual(lpqsRestrictions->lpServiceClassId, &IANAGuid))
|
|
{
|
|
dwLocalFlags |= IANALOOK;
|
|
dwControlFlags &= ~(LUP_RETURN_ADDR);
|
|
}
|
|
|
|
//
|
|
// Compute whether this is some sort of name lookup. Do this
|
|
// here since we've two places below that need to test for it.
|
|
//
|
|
|
|
fNameLook = GuidEqual(lpqsRestrictions->lpServiceClassId, &HostnameGuid)
|
|
||
|
|
IS_SVCID_TCP(lpqsRestrictions->lpServiceClassId)
|
|
||
|
|
IS_SVCID_UDP(lpqsRestrictions->lpServiceClassId)
|
|
||
|
|
GuidEqual(lpqsRestrictions->lpServiceClassId, &InetHostName);
|
|
|
|
if(!pwszServiceName
|
|
||
|
|
!pwszServiceName[0])
|
|
{
|
|
//
|
|
// the service name is NULL. Only allow this in certain cases
|
|
//
|
|
if(fNameLook)
|
|
{
|
|
dwLocalFlags |= LOCALLOOK;
|
|
pwszServiceName = L"";
|
|
}
|
|
else if((dwLocalFlags & REVERSELOOK)
|
|
&&
|
|
lpqsRestrictions->lpcsaBuffer
|
|
&&
|
|
(lpqsRestrictions->dwNumberOfCsAddrs == 1))
|
|
{
|
|
//
|
|
// there had better be an address in the CSADDR
|
|
//
|
|
|
|
struct sockaddr_in * psock;
|
|
PCHAR pszAddr;
|
|
|
|
psock = (struct sockaddr_in *)
|
|
lpqsRestrictions->lpcsaBuffer->RemoteAddr.lpSockaddr;
|
|
|
|
pszAddr = inet_ntoa(psock->sin_addr);
|
|
if(!pszAddr)
|
|
{
|
|
goto badparm;
|
|
}
|
|
|
|
pwszServiceName = wszString;
|
|
|
|
if(!MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pszAddr,
|
|
-1,
|
|
pwszServiceName,
|
|
1000))
|
|
{
|
|
DWORD err = GetLastError();
|
|
|
|
SockDereferenceHooker( hookerInfo );
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError( err );
|
|
return(SOCKET_ERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
badparm:
|
|
SockDereferenceHooker( hookerInfo );
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError(WSA_INVALID_PARAMETER);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
}
|
|
else if(fNameLook)
|
|
{
|
|
//
|
|
// it's some kind of name lookup. So, let's see if it is a special
|
|
// name
|
|
//
|
|
PCHAR pszAnsiName = GetAnsiNameRnR(pwszServiceName, 0);
|
|
|
|
if(!_stricmp(pszAnsiName, "localhost")
|
|
||
|
|
!_stricmp(pszAnsiName, "loopback"))
|
|
{
|
|
dwLocalFlags |= LOCALLOOK | LOOPLOOK;
|
|
}
|
|
else if( IsLocalComputerName( lpProviderId, pszAnsiName ) )
|
|
{
|
|
dwLocalFlags |= LOCALLOOK;
|
|
}
|
|
SOCK_FREE_HEAP(pszAnsiName);
|
|
}
|
|
|
|
//
|
|
// Compute protocols to return, or return them all
|
|
//
|
|
if(lpqsRestrictions->lpafpProtocols)
|
|
{
|
|
//
|
|
// Make certain at least one TCP/IP protocol is being requested
|
|
//
|
|
|
|
INT i;
|
|
DWORD dwNum = lpqsRestrictions->dwNumberOfProtocols;
|
|
|
|
nProt = 0;
|
|
|
|
for(i = 0; dwNum--;)
|
|
{
|
|
if((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET)
|
|
||
|
|
(lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC)
|
|
)
|
|
|
|
{
|
|
switch(lpqsRestrictions->lpafpProtocols[i].iProtocol)
|
|
{
|
|
case IPPROTO_UDP:
|
|
nProt |= UDP_BIT;
|
|
break;
|
|
case IPPROTO_TCP:
|
|
nProt |= TCP_BIT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(!nProt)
|
|
{
|
|
//
|
|
// if the caller doesn't want addresses, why bother?
|
|
//
|
|
SockDereferenceHooker( hookerInfo );
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError(WSANO_DATA);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nProt = UDP_BIT | TCP_BIT;
|
|
}
|
|
|
|
//
|
|
// Complete computation of protocols. We might have information in
|
|
// the query string that helps us, and if so, we need
|
|
// to fetch the servent for that specification.
|
|
//
|
|
|
|
nProt &= GetServerAndProtocolsFromString(
|
|
hookerInfo,
|
|
lpqsRestrictions->lpszQueryString,
|
|
lpqsRestrictions->lpServiceClassId,
|
|
&sent
|
|
);
|
|
|
|
if(sent)
|
|
{
|
|
if(nProt & UDP_BIT)
|
|
{
|
|
dwUdpPort = ntohs(sent->s_port);
|
|
dwTcpPort = NOPORTDEFINED;
|
|
}
|
|
else if(nProt & TCP_BIT)
|
|
{
|
|
dwTcpPort = ntohs(sent->s_port);
|
|
dwUdpPort = NOPORTDEFINED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(nProt & UDP_BIT)
|
|
{
|
|
dwUdpPort = FetchPortFromClassInfo(UDP_PORT,
|
|
lpqsRestrictions->lpServiceClassId,
|
|
lpServiceClassInfo);
|
|
}
|
|
else
|
|
{
|
|
dwUdpPort = NOPORTDEFINED;
|
|
}
|
|
if(nProt & TCP_BIT)
|
|
{
|
|
dwTcpPort = FetchPortFromClassInfo(TCP_PORT,
|
|
lpqsRestrictions->lpServiceClassId,
|
|
lpServiceClassInfo);
|
|
}
|
|
else
|
|
{
|
|
dwTcpPort = NOPORTDEFINED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if no protocol info so far, then this has to be a host name lookup
|
|
// of some sort or it is an error
|
|
//
|
|
if((dwTcpPort == NOPORTDEFINED) && (dwUdpPort == NOPORTDEFINED))
|
|
{
|
|
if((dwLocalFlags & (REVERSELOOK | LOCALLOOK | IANALOOK))
|
|
||
|
|
GuidEqual(lpqsRestrictions->lpServiceClassId, &HostnameGuid)
|
|
||
|
|
GuidEqual(lpqsRestrictions->lpServiceClassId, &InetHostName) )
|
|
{
|
|
dwUdpPort = NOPORTDEFINED;
|
|
dwTcpPort = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
SockDereferenceHooker( hookerInfo );
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError(WSANO_DATA);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// one final check. If the name does not contain a dotted part,
|
|
// add the home domain to it.
|
|
//
|
|
|
|
if(!(dwLocalFlags & (IANALOOK | LOCALLOOK))
|
|
&&
|
|
!wcschr(pwszServiceName, L'.'))
|
|
{
|
|
//
|
|
// not dotted. Mark we need the domain name
|
|
//
|
|
|
|
|
|
if(dwLocalFlags & REVERSELOOK)
|
|
{
|
|
goto badparm;
|
|
}
|
|
dwLocalFlags |= NEEDDOMAIN;
|
|
}
|
|
|
|
|
|
//
|
|
// It has passed muster. Allocate a context for it.
|
|
//
|
|
|
|
dwHostLen = (wcslen(pwszServiceName) + 1) *
|
|
sizeof(WCHAR);
|
|
|
|
|
|
pdrc = RnR2MakeContext(0, dwHostLen);
|
|
|
|
if(!pdrc)
|
|
{
|
|
SockDereferenceHooker( hookerInfo );
|
|
SOCK_EXIT( "NSPLookupServiceBegin", SOCKET_ERROR, TRUE );
|
|
SetLastError(WSA_NOT_ENOUGH_MEMORY);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
//
|
|
// save things in the context
|
|
//
|
|
|
|
pdrc->gdType = *lpqsRestrictions->lpServiceClassId;
|
|
pdrc->dwControlFlags = dwControlFlags;
|
|
pdrc->dwTcpPort = dwTcpPort;
|
|
pdrc->dwUdpPort = dwUdpPort;
|
|
pdrc->fFlags = dwLocalFlags;
|
|
pdrc->gdProviderId = *lpProviderId;
|
|
pdrc->dwNameSpace = lpqsRestrictions->dwNameSpace;
|
|
pdrc->HookerInfo = hookerInfo;
|
|
|
|
wcscpy(pdrc->wcName, pwszServiceName);
|
|
|
|
RnR2ReleaseContext(pdrc);
|
|
SOCK_EXIT( "NSPLookupServiceBegin", NO_ERROR, FALSE );
|
|
|
|
*lphLookup = (HANDLE)pdrc;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceNext(
|
|
IN HANDLE hLookup,
|
|
IN DWORD dwControlFlags,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
OUT LPWSAQUERYSETW lpqsResults
|
|
)
|
|
{
|
|
/*++
|
|
Routine Description:
|
|
The continuation of LookupBegin. This tries to lookup the service
|
|
based on the parameters in the context
|
|
--*/
|
|
|
|
INT err;
|
|
PDNS_RNR_CONTEXT pdrc;
|
|
PBYTE pData = (PBYTE)(lpqsResults + 1);
|
|
LONG lSpare = (LONG)*lpdwBufferLength - lpqsResults->dwSize;
|
|
LPSTR pAnsiName = NULL;
|
|
PHOSTENT hostEntry = NULL;
|
|
PCHAR pBuff = (PCHAR)(lpqsResults + 1);
|
|
DWORD dwTaken;
|
|
LONG lFree, lInstance;
|
|
PCHAR pszDomain, pszName;
|
|
struct hostent LocalHostEntry;
|
|
PINT local_addr_list[2];
|
|
INT LocalAddress;
|
|
WSAQUERYSETW wsaqDummy;
|
|
struct servent * sent = NULL;
|
|
CHAR szComputerName[20];
|
|
LONG lSizeOf;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
if(*lpdwBufferLength < sizeof(WSAQUERYSETW))
|
|
{
|
|
lpqsResults = &wsaqDummy;
|
|
}
|
|
RtlZeroMemory(lpqsResults, sizeof(WSAQUERYSETW));
|
|
lpqsResults->dwNameSpace = NS_DNS;
|
|
lpqsResults->dwSize = sizeof(WSAQUERYSETW);
|
|
|
|
lFree = (LONG)(*lpdwBufferLength - sizeof(WSAQUERYSETW));
|
|
|
|
pdrc = RnR2GetContext(hLookup);
|
|
if(!pdrc)
|
|
{
|
|
SetLastError(WSA_INVALID_HANDLE);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
//
|
|
// a valid context. Get the instance
|
|
//
|
|
|
|
EnterCriticalSection(&csRnRLock);
|
|
lInstance = ++pdrc->lInstance;
|
|
if(dwControlFlags & LUP_FLUSHPREVIOUS)
|
|
{
|
|
lInstance = ++pdrc->lInstance;
|
|
}
|
|
LeaveCriticalSection(&csRnRLock);
|
|
|
|
pszDomain = 0;
|
|
|
|
pAnsiName = GetAnsiNameRnR(pdrc->wcName, pszDomain);
|
|
if(!pAnsiName)
|
|
{
|
|
err = WSA_NOT_ENOUGH_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
SetLastError(NO_ERROR); // start clean
|
|
|
|
//
|
|
// call the proper function to do this
|
|
//
|
|
|
|
if(pdrc->fFlags & IANALOOK)
|
|
{
|
|
USHORT port;
|
|
|
|
//
|
|
// This is a lookup of an IANA service name and the caller
|
|
// wants the type returned. The RNR conventions are that
|
|
// these names look like 21/ftp, that being something our
|
|
// bind code can't handle. So, check for such a name and
|
|
// ignore the prefix port for the lookup. If the service
|
|
// cannot be found, then use that port and assume tcp.
|
|
//
|
|
|
|
BOOL IsTcp;
|
|
DWORD nProt;
|
|
|
|
nProt = GetServerAndProtocolsFromString(
|
|
pdrc->HookerInfo,
|
|
pdrc->wcName,
|
|
&HostnameGuid,
|
|
&sent);
|
|
|
|
|
|
if(!sent)
|
|
{
|
|
err = WSATYPE_NOT_FOUND;
|
|
goto Done;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// found it. Get the information from the entry
|
|
//
|
|
port = ntohs(sent->s_port);
|
|
IsTcp = (_stricmp("tcp", sent->s_proto) == 0);
|
|
pszName = sent->s_name;
|
|
}
|
|
|
|
//
|
|
// Make a GUID and copy it into the context.
|
|
|
|
if(IsTcp)
|
|
{
|
|
SET_TCP_SVCID(&pdrc->gdType, port);
|
|
pdrc->dwTcpPort = (DWORD)port;
|
|
pdrc->dwUdpPort = NOPORTDEFINED;
|
|
}
|
|
else
|
|
{
|
|
SET_UDP_SVCID(&pdrc->gdType, port);
|
|
pdrc->dwUdpPort = (DWORD)port;
|
|
pdrc->dwTcpPort = NOPORTDEFINED;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// If this is a RES_SERVICE, just return the address.
|
|
//
|
|
|
|
if(pdrc->dwControlFlags & LUP_RES_SERVICE)
|
|
{
|
|
if(lInstance)
|
|
{
|
|
NoMoreData:
|
|
err = WSA_E_NO_MORE;
|
|
goto Done;
|
|
}
|
|
//
|
|
// Make up a host entry that has one address, of all zero.
|
|
// fill in the other items just in case.
|
|
//
|
|
hostEntry = &LocalHostEntry;
|
|
hostEntry->h_name = pAnsiName;
|
|
hostEntry->h_aliases = 0;
|
|
hostEntry->h_addr_list = (PCHAR *)local_addr_list;
|
|
local_addr_list[0] = &LocalAddress;
|
|
LocalAddress = 0;
|
|
local_addr_list[1] = 0;
|
|
hostEntry->h_addrtype = AF_INET;
|
|
hostEntry->h_length = sizeof(ULONG);
|
|
}
|
|
else if(!(hostEntry = pdrc->phent))
|
|
{
|
|
//
|
|
// It's some form of host lookup and we don't yet have
|
|
// a saved hostent for it. See if we can get one
|
|
//
|
|
if(pdrc->fFlags & REVERSELOOK)
|
|
{
|
|
|
|
DWORD dwIp = inet_addr(pAnsiName);
|
|
|
|
SockPreApiCallout();
|
|
|
|
hostEntry = pdrc->HookerInfo->gethostbyaddr(
|
|
(PCHAR)&dwIp,
|
|
4,
|
|
AF_INET
|
|
);
|
|
|
|
if( hostEntry == NULL ) {
|
|
|
|
err = pdrc->HookerInfo->WSAGetLastError();
|
|
SOCK_ASSERT( err != NO_ERROR );
|
|
SockPostApiCallout();
|
|
goto Done;
|
|
|
|
}
|
|
|
|
SockPostApiCallout();
|
|
}
|
|
else if(!(pdrc->fFlags & LOCALLOOK))
|
|
{
|
|
//
|
|
// a real name lookup. See which provider type to use
|
|
//
|
|
|
|
//
|
|
// if in the 2:1 mapper, just defer the call to
|
|
// someone else.
|
|
//
|
|
|
|
SockPreApiCallout();
|
|
|
|
hostEntry = pdrc->HookerInfo->gethostbyname(
|
|
pAnsiName
|
|
);
|
|
|
|
if( hostEntry == NULL ) {
|
|
|
|
err = pdrc->HookerInfo->WSAGetLastError();
|
|
SOCK_ASSERT( err != NO_ERROR );
|
|
SockPostApiCallout();
|
|
goto Done;
|
|
|
|
}
|
|
|
|
SockPostApiCallout();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the caller is looking for information about the
|
|
// local machine. So return either the localhostent
|
|
// information, the WINS form of the DNS information,
|
|
// or the real DNS information. This is important to
|
|
// get right in order for apps to work properly
|
|
//
|
|
|
|
INT result;
|
|
CHAR szLocalHostName[256]; // allow plenty of room
|
|
|
|
//
|
|
// in the 2:1 mapper we have to first get our local host
|
|
// name and then ask for the hostent structure. It's really
|
|
// the "right" way to do this, but we take a short-cut when
|
|
// we own the provider. Note there's no way to know how
|
|
// much space to allocate, so if 1000 bytes is insufficient,
|
|
// it simply fails, but I suspect many other things fail
|
|
// we well.
|
|
//
|
|
|
|
SockPreApiCallout();
|
|
|
|
result = pdrc->HookerInfo->gethostname(
|
|
szLocalHostName,
|
|
sizeof(szLocalHostName)
|
|
);
|
|
|
|
if( result == SOCKET_ERROR ) {
|
|
|
|
err = pdrc->HookerInfo->WSAGetLastError();
|
|
SOCK_ASSERT( err != NO_ERROR );
|
|
SockPostApiCallout();
|
|
goto Done;
|
|
|
|
}
|
|
|
|
hostEntry = pdrc->HookerInfo->gethostbyname(
|
|
pAnsiName
|
|
);
|
|
|
|
if( hostEntry == NULL ) {
|
|
|
|
err = pdrc->HookerInfo->WSAGetLastError();
|
|
SOCK_ASSERT( err != NO_ERROR );
|
|
SockPostApiCallout();
|
|
goto Done;
|
|
|
|
}
|
|
|
|
SockPostApiCallout();
|
|
}
|
|
|
|
SOCK_ASSERT( hostEntry != NULL );
|
|
|
|
//
|
|
// copy the host entry so we can keep a local copy of
|
|
// it
|
|
|
|
pdrc->phent = hostEntry = CopyHostEntry(hostEntry,
|
|
0,
|
|
0,
|
|
&lSizeOf,
|
|
FALSE);
|
|
pdrc->dwHostSize = (DWORD)lSizeOf;
|
|
}
|
|
|
|
SOCK_ASSERT( hostEntry != NULL );
|
|
|
|
//
|
|
// Got the data. See if we've returned all of the results yet.
|
|
//
|
|
|
|
if(!lInstance)
|
|
{
|
|
pszName = hostEntry->h_name;
|
|
}
|
|
else
|
|
{
|
|
if((pdrc->dwControlFlags & LUP_RETURN_ALIASES)
|
|
&&
|
|
hostEntry->h_aliases)
|
|
{
|
|
LONG x;
|
|
|
|
for(x = 0; x < lInstance; x++)
|
|
{
|
|
if(hostEntry->h_aliases[x] == NULL)
|
|
{
|
|
goto NoMoreData;
|
|
}
|
|
}
|
|
pszName = hostEntry->h_aliases[x - 1];
|
|
lpqsResults->dwOutputFlags |= RESULT_IS_ALIAS;
|
|
}
|
|
else
|
|
{
|
|
goto NoMoreData;
|
|
}
|
|
}
|
|
} // IANALOOK
|
|
|
|
lpqsResults->dwNameSpace = NS_DNS;
|
|
|
|
//
|
|
// we've an answer. So make the response
|
|
//
|
|
|
|
if(pdrc->dwControlFlags & LUP_RETURN_TYPE)
|
|
{
|
|
lFree -= sizeof(GUID);
|
|
if(lFree < 0)
|
|
{
|
|
err = WSAEFAULT;
|
|
}
|
|
else
|
|
{
|
|
lpqsResults->lpServiceClassId = (LPGUID)pBuff;
|
|
*lpqsResults->lpServiceClassId = pdrc->gdType;
|
|
pBuff += sizeof(GUID);
|
|
}
|
|
}
|
|
|
|
if(pdrc->dwControlFlags & LUP_RETURN_ADDR)
|
|
{
|
|
lpqsResults->lpcsaBuffer = (PVOID)pBuff;
|
|
err = PackCsAddr(
|
|
hostEntry,
|
|
pdrc->dwUdpPort,
|
|
pdrc->dwTcpPort,
|
|
(PVOID)pBuff,
|
|
&lFree,
|
|
&dwTaken,
|
|
&lpqsResults->dwNumberOfCsAddrs,
|
|
(pdrc->fFlags & REVERSELOOK) == 1);
|
|
if(err == NO_ERROR)
|
|
{
|
|
pBuff += dwTaken;
|
|
}
|
|
}
|
|
|
|
if(pdrc->dwControlFlags & LUP_RETURN_BLOB)
|
|
{
|
|
if(GuidEqual(&pdrc->gdType, &InetHostName)
|
|
||
|
|
GuidEqual(&pdrc->gdType, &AddressGuid) )
|
|
{
|
|
//
|
|
// return the raw hostent for those that like that
|
|
//
|
|
|
|
LONG lTaken;
|
|
|
|
lpqsResults->lpBlob = (LPBLOB)pBuff;
|
|
lFree -= sizeof(BLOB);
|
|
pBuff += sizeof(BLOB);
|
|
if(CopyHostEntry(hostEntry,
|
|
pBuff,
|
|
lFree,
|
|
&lTaken,
|
|
TRUE))
|
|
{
|
|
lpqsResults->lpBlob->pBlobData = pBuff;
|
|
lpqsResults->lpBlob->cbSize = lTaken;
|
|
pBuff += lTaken;
|
|
}
|
|
else
|
|
{
|
|
err = WSAEFAULT;
|
|
}
|
|
lFree -= lTaken;
|
|
}
|
|
else if((pdrc->fFlags & IANALOOK)
|
|
&&
|
|
sent)
|
|
{
|
|
//
|
|
// a service lookup. Return the servent
|
|
//
|
|
|
|
LONG lTaken;
|
|
|
|
lpqsResults->lpBlob = (LPBLOB)pBuff;
|
|
lFree -= sizeof(BLOB);
|
|
pBuff += sizeof(BLOB);
|
|
if(CopyServEntry(sent,
|
|
pBuff,
|
|
lFree,
|
|
&lTaken,
|
|
TRUE))
|
|
{
|
|
lpqsResults->lpBlob->pBlobData = pBuff;
|
|
lpqsResults->lpBlob->cbSize = lTaken;
|
|
pBuff += lTaken;
|
|
}
|
|
else
|
|
{
|
|
err = WSAEFAULT;
|
|
}
|
|
lFree -= lTaken;
|
|
}
|
|
}
|
|
|
|
if(pdrc->dwControlFlags & LUP_RETURN_NAME)
|
|
{
|
|
PWCHAR pszString;
|
|
DWORD dwLen;
|
|
|
|
//
|
|
// and the caller wants the name. Make sure it fits
|
|
//
|
|
|
|
if(AllocateUnicodeString(pszName, &pszString) != NO_ERROR)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
dwLen = (wcslen(pszString) + 1) * sizeof(WCHAR);
|
|
lFree -= dwLen;
|
|
if(lFree < 0)
|
|
{
|
|
err = WSAEFAULT;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(
|
|
pBuff,
|
|
pszString,
|
|
dwLen);
|
|
lpqsResults->lpszServiceInstanceName = (WCHAR *)pBuff;
|
|
pBuff += dwLen;
|
|
}
|
|
SOCK_FREE_HEAP(pszString);
|
|
}
|
|
|
|
Done:
|
|
if(pAnsiName)
|
|
{
|
|
SOCK_FREE_HEAP(pAnsiName);
|
|
}
|
|
if(err != NO_ERROR)
|
|
{
|
|
SetLastError(err);
|
|
if(err == WSAEFAULT)
|
|
{
|
|
//
|
|
// If this is the error, lFree should be the value
|
|
// -(extra bytes needed)
|
|
//
|
|
*lpdwBufferLength -= lFree;
|
|
EnterCriticalSection(&csRnRLock);
|
|
--pdrc->lInstance;
|
|
LeaveCriticalSection(&csRnRLock);
|
|
}
|
|
err = (DWORD)SOCKET_ERROR;
|
|
}
|
|
RnR2ReleaseContext(pdrc);
|
|
return(err);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPLookupServiceEnd(
|
|
IN HANDLE hLookup
|
|
)
|
|
{
|
|
PDNS_RNR_CONTEXT pdrc;
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
pdrc = RnR2GetContext(hLookup);
|
|
if(!pdrc)
|
|
{
|
|
|
|
SetLastError(WSA_INVALID_HANDLE);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
RnR2ReleaseContext(pdrc); // get rid of it
|
|
RnR2ReleaseContext(pdrc); // and close it. Context cleanup is
|
|
// done on the last derefernce.
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPUnInstallNameSpace(
|
|
IN LPGUID lpProviderId
|
|
)
|
|
{
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPCleanup(
|
|
IN LPGUID lpProviderId
|
|
)
|
|
{
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
if(!InterlockedDecrement(&lStartupCount))
|
|
{
|
|
RnR2Cleanup(); // zap all contexts
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPSetService(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
|
|
IN LPWSAQUERYSETW lpqsRegInfo,
|
|
IN WSAESETSERVICEOP essOperation,
|
|
IN DWORD dwControlFlags
|
|
)
|
|
{
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Since DNS is a static database, there's nothing to do
|
|
//
|
|
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPInstallServiceClass(
|
|
IN LPGUID lpProviderId,
|
|
IN LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
)
|
|
{
|
|
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Must be done manually
|
|
//
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPRemoveServiceClass(
|
|
IN LPGUID lpProviderId,
|
|
IN LPGUID lpServiceCallId
|
|
)
|
|
{
|
|
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
INT WINAPI
|
|
NSPGetServiceClassInfo(
|
|
IN LPGUID lpProviderId,
|
|
IN OUT LPDWORD lpdwBufSize,
|
|
IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo
|
|
)
|
|
{
|
|
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Fetch the class info stuff from DNS
|
|
//
|
|
|
|
SetLastError(WSASERVICE_NOT_FOUND);
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
|
|
INT WINAPI
|
|
NSPStartup(
|
|
IN LPGUID lpProviderId,
|
|
IN OUT LPNSP_ROUTINE lpsnpRoutines)
|
|
{
|
|
DWORD dwSize = min(sizeof(nsrVector), lpsnpRoutines->cbSize);
|
|
INT err;
|
|
|
|
err = SockEnterApi( FALSE, FALSE );
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SetLastError( err );
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// BUGBUG. If no size is provided, assume it is big enough!!!!
|
|
//
|
|
|
|
if( InterlockedIncrement(&lStartupCount) == 1 ) {
|
|
|
|
InitializeCriticalSection( &csRnRLock );
|
|
|
|
}
|
|
|
|
if(!dwSize)
|
|
{
|
|
dwSize = sizeof(nsrVector);
|
|
}
|
|
|
|
RtlCopyMemory(lpsnpRoutines,
|
|
&nsrVector,
|
|
dwSize);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
//
|
|
// Two helper routines to assist CopyHostEntry. These compute
|
|
// the space needed to hold the alias and address structures
|
|
// respectively. They are called only once each, and therefore
|
|
// could have been in-line, but doing it this way makes it easier
|
|
// to read. The extra cost is small, so readbility won out. Now if
|
|
// C had an inline directive ...
|
|
//
|
|
DWORD
|
|
GetAliasSize(PCHAR * pal, PDWORD pdwCount)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
dwSize = sizeof(PCHAR);
|
|
*pdwCount = 1;
|
|
|
|
if(pal)
|
|
{
|
|
for(; *pal; pal++)
|
|
{
|
|
dwSize += sizeof(PCHAR);
|
|
|
|
dwSize += strlen(*pal) + 1;
|
|
|
|
*pdwCount += 1;
|
|
}
|
|
}
|
|
return(dwSize);
|
|
}
|
|
|
|
DWORD
|
|
GetAddrSize(struct hostent * ph, PDWORD pdwAddCount)
|
|
{
|
|
DWORD dwSize = sizeof(PCHAR);
|
|
PCHAR * paddr;
|
|
|
|
*pdwAddCount = 1;
|
|
for(paddr = ph->h_addr_list; *paddr; paddr++)
|
|
{
|
|
dwSize += ph->h_length;
|
|
dwSize += sizeof(PCHAR);
|
|
*pdwAddCount += 1;
|
|
}
|
|
return(dwSize);
|
|
}
|
|
|
|
|
|
//
|
|
// Turn a list of addresses into a list of offsets
|
|
//
|
|
|
|
VOID
|
|
FixList(PCHAR ** List,
|
|
PCHAR Base)
|
|
{
|
|
PCHAR * Addr = *List;
|
|
|
|
*List = (PCHAR *)((PCHAR)*List - Base);
|
|
|
|
while(*Addr)
|
|
{
|
|
*Addr = (PCHAR)((PCHAR)*Addr - Base);
|
|
Addr++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy a hostent structure into a freshly allocate block of memory or
|
|
// into a provided block of size lSizeoOf.
|
|
// Args work as follows:
|
|
//
|
|
// phent -- the stuff to be copied
|
|
// pbAllocated -- if non-NULL, the memory in which to make a copy of phent
|
|
// if NULL, allocate memory to hold this.
|
|
// lSizeOf -- if pbAllocated in non-NULL, the size of the memory at
|
|
// that address
|
|
// plTake -- a pointer to a LONG where the amount of memory needed to make
|
|
// a copy of phent is returned.
|
|
//
|
|
// the copied hostent is placed in a contiguous chunk of memory so
|
|
// that if pbAllocated in non-NULL the first *plTaken bytes will
|
|
// have been used to hold the structure.
|
|
//
|
|
// Return:
|
|
// 0 -- insufficient memory to do the copy
|
|
// != 0 -- the address of the new hostent
|
|
//
|
|
|
|
struct hostent *
|
|
CopyHostEntry(
|
|
struct hostent * phent,
|
|
PBYTE pbAllocated,
|
|
LONG lSizeOf,
|
|
PLONG plTaken,
|
|
BOOL fOffsets
|
|
)
|
|
{
|
|
PBYTE pb;
|
|
struct hostent * ph;
|
|
DWORD dwSize, dwAddCount, dwAlCount;
|
|
|
|
dwSize = sizeof(struct hostent) +
|
|
GetAliasSize(phent->h_aliases, &dwAlCount) +
|
|
GetAddrSize(phent, &dwAddCount) +
|
|
strlen(phent->h_name) + 1;
|
|
|
|
if(!(pb = pbAllocated))
|
|
{
|
|
pb = (PBYTE)AllocLocal(dwSize);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// align it first. This is done to insure that if this
|
|
// space is within another buffer, as it will be when
|
|
// returning a BLOB through a LoookupServiceNext, that
|
|
// the buffer is left aligned to hold a string. Note it
|
|
// is not left aligned to hold a structure on the assumption
|
|
// that any structures are packed ahead of this. If
|
|
// it is ever necessary to guarantee address alignment,
|
|
// replace the ALIGN_WORD with ALIGN_DWORD.
|
|
//
|
|
|
|
dwSize = ROUND_UP_COUNT(dwSize, ALIGN_WORD);
|
|
if(lSizeOf < (LONG)dwSize)
|
|
{
|
|
pb = 0; // insufficient space provided.
|
|
}
|
|
}
|
|
|
|
*plTaken = (LONG)dwSize;
|
|
|
|
if(pb)
|
|
{
|
|
PCHAR *pcs, *pcd;
|
|
|
|
ph = (struct hostent *)pb;
|
|
ph->h_addr_list = (PCHAR *)(ph + 1);
|
|
ph->h_aliases = &ph->h_addr_list[dwAddCount];
|
|
pb = (PBYTE)&ph->h_aliases[dwAlCount];
|
|
|
|
//
|
|
// copy the basic structure
|
|
//
|
|
|
|
ph->h_addrtype = phent->h_addrtype;
|
|
ph->h_length = phent->h_length;
|
|
|
|
//
|
|
// The layout in the string space is the addresses first, then
|
|
// the aliases, then the name.
|
|
//
|
|
|
|
pcs = phent->h_addr_list;
|
|
pcd = ph->h_addr_list;
|
|
|
|
if(pcs)
|
|
{
|
|
while(*pcs)
|
|
{
|
|
*pcd = (PCHAR)pb;
|
|
RtlCopyMemory(pb, *pcs, phent->h_length);
|
|
pb += phent->h_length;
|
|
pcd++;
|
|
pcs++;
|
|
}
|
|
}
|
|
*pcd = 0;
|
|
|
|
//
|
|
// copy the aliases
|
|
//
|
|
|
|
pcs = phent->h_aliases;
|
|
pcd = ph->h_aliases;
|
|
if(pcs)
|
|
{
|
|
while(*pcs)
|
|
{
|
|
DWORD dwLen = strlen(*pcs) + 1;
|
|
|
|
*pcd = (PCHAR)pb;
|
|
RtlCopyMemory(pb, *pcs, dwLen);
|
|
pb += dwLen;
|
|
pcd++;
|
|
pcs++;
|
|
}
|
|
}
|
|
*pcd = 0;
|
|
|
|
//
|
|
// finally the name
|
|
//
|
|
|
|
if(phent->h_name)
|
|
{
|
|
ph->h_name = (PCHAR)pb;
|
|
strcpy(pb, phent->h_name);
|
|
}
|
|
else
|
|
{
|
|
ph->h_name = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ph = 0;
|
|
}
|
|
|
|
//
|
|
// if relative offsets are needed, go through the address to make them so
|
|
//
|
|
|
|
if(ph && fOffsets)
|
|
{
|
|
ph->h_name = (PCHAR)(ph->h_name - (PCHAR)ph);
|
|
FixList(&ph->h_aliases, (PCHAR)ph);
|
|
FixList(&ph->h_addr_list, (PCHAR)ph);
|
|
}
|
|
return(ph);
|
|
}
|
|
|
|
//
|
|
// Copy a servent. Same comments as apply above for hostent copying
|
|
//
|
|
struct servent *
|
|
CopyServEntry(
|
|
struct servent * sent,
|
|
PBYTE pbAllocated,
|
|
LONG lSizeOf,
|
|
PLONG plTaken,
|
|
BOOL fOffsets
|
|
)
|
|
{
|
|
PBYTE pb;
|
|
struct servent * ps;
|
|
DWORD dwSize, dwAlCount, dwNameSize;
|
|
|
|
dwNameSize = strlen(sent->s_name) + 1;
|
|
dwSize = sizeof(struct servent) +
|
|
GetAliasSize(sent->s_aliases, &dwAlCount) +
|
|
dwNameSize +
|
|
strlen(sent->s_proto) + 1;
|
|
|
|
|
|
if(!(pb = pbAllocated))
|
|
{
|
|
pb = (PBYTE)AllocLocal(dwSize);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// align it first. This is done to insure that if this
|
|
// space is within another buffer, as it will be when
|
|
// returning a BLOB through a LoookupServiceNext, that
|
|
// the buffer is left aligned to hold a string. Note it
|
|
// is not left aligned to hold a structure on the assumption
|
|
// that any structures are packed ahead of this. If
|
|
// it is ever necessary to guarantee address alignment,
|
|
// replace the ALIGN_WORD with ALIGN_DWORD.
|
|
//
|
|
|
|
dwSize = ROUND_UP_COUNT(dwSize, ALIGN_WORD);
|
|
if(lSizeOf < (LONG)dwSize)
|
|
{
|
|
pb = 0; // insufficient space provided.
|
|
}
|
|
}
|
|
|
|
*plTaken = (LONG)dwSize;
|
|
|
|
if(pb)
|
|
{
|
|
PCHAR *pcs, *pcd;
|
|
|
|
ps= (struct servent *)pb;
|
|
ps->s_aliases = (PCHAR *)(ps + 1);
|
|
pb = (PBYTE)&ps->s_aliases[dwAlCount];
|
|
|
|
//
|
|
// copy the basic structure
|
|
//
|
|
|
|
ps->s_port = sent->s_port;
|
|
|
|
//
|
|
// The layout in the string space is the aliases first, then
|
|
// the name, then the protocol string
|
|
//
|
|
|
|
|
|
// copy the aliases
|
|
//
|
|
pcs = sent->s_aliases;
|
|
pcd = ps->s_aliases;
|
|
if(pcs)
|
|
{
|
|
while(*pcs)
|
|
{
|
|
DWORD dwLen = strlen(*pcs) + 1;
|
|
|
|
*pcd = (PCHAR)pb;
|
|
RtlCopyMemory(pb, *pcs, dwLen);
|
|
pb += dwLen;
|
|
pcd++;
|
|
pcs++;
|
|
}
|
|
}
|
|
*pcd = 0;
|
|
|
|
// now the two strings
|
|
|
|
ps->s_name = (PCHAR)pb;
|
|
RtlMoveMemory(pb, sent->s_name, dwNameSize);
|
|
pb += dwNameSize;
|
|
ps->s_proto = (PCHAR)pb;
|
|
strcpy(pb, sent->s_proto);
|
|
}
|
|
else
|
|
{
|
|
ps = 0;
|
|
}
|
|
if(ps && fOffsets)
|
|
{
|
|
ps->s_name = (PCHAR)(ps->s_name - (PCHAR)ps);
|
|
ps->s_proto = (PCHAR)(ps->s_proto - (PCHAR)ps);
|
|
FixList(&ps->s_aliases, (PCHAR)ps);
|
|
}
|
|
|
|
return(ps);
|
|
}
|
|
|
|
|
|
DWORD
|
|
AllocateUnicodeString (
|
|
IN LPSTR lpAnsi,
|
|
IN OUT PWCHAR *lppUnicode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a Unicode String intialized with the Ansi one.
|
|
Caller must free with SOCK_FREE_HEAP().
|
|
|
|
Arguments:
|
|
|
|
lpAnsi - ANSI string that is used to init the Unicode string
|
|
|
|
lppUnicode - address to receive pointer to Unicode string.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR if successful. Win32 error otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPWSTR UnicodeString;
|
|
INT err;
|
|
DWORD dwAnsiLen;
|
|
|
|
*lppUnicode = NULL ;
|
|
|
|
//
|
|
// handle the trivial case
|
|
//
|
|
if (!lpAnsi)
|
|
{
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
//
|
|
// allocate the memory
|
|
//
|
|
dwAnsiLen = strlen(lpAnsi) + 1;
|
|
|
|
UnicodeString = (LPWSTR)SOCK_ALLOCATE_HEAP(dwAnsiLen * sizeof(WCHAR));
|
|
|
|
if (!UnicodeString)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
|
|
//
|
|
// convert it
|
|
//
|
|
|
|
err = MultiByteToWideChar(
|
|
CP_ACP, // better by ANSI
|
|
0,
|
|
lpAnsi,
|
|
-1, // it's NULL terminated
|
|
UnicodeString,
|
|
dwAnsiLen ); // # of wide characters available
|
|
|
|
if (!err)
|
|
{
|
|
SOCK_FREE_HEAP(UnicodeString) ;
|
|
return (GetLastError());
|
|
}
|
|
|
|
*lppUnicode = UnicodeString;
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
BOOL
|
|
IsLocalComputerName(
|
|
IN LPGUID ProviderId,
|
|
IN LPSTR AnsiName
|
|
)
|
|
{
|
|
|
|
PHOOKER_INFORMATION hookerInfo;
|
|
LPSTR dot;
|
|
INT result;
|
|
BOOL value;
|
|
CHAR name[256];
|
|
|
|
value = FALSE;
|
|
|
|
hookerInfo = SockFindAndReferenceHooker( ProviderId );
|
|
|
|
if( hookerInfo == NULL ) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
SockPreApiCallout();
|
|
|
|
result = hookerInfo->gethostname(
|
|
name,
|
|
sizeof(name)
|
|
);
|
|
|
|
if( result == SOCKET_ERROR ) {
|
|
|
|
SockPostApiCallout();
|
|
goto exit;
|
|
|
|
}
|
|
|
|
SockPostApiCallout();
|
|
|
|
if( _stricmp( name, AnsiName ) == 0 ) {
|
|
|
|
value = TRUE;
|
|
goto exit;
|
|
|
|
}
|
|
|
|
dot = name;
|
|
|
|
while( *dot != '\0' && *dot != '.' ) {
|
|
|
|
dot++;
|
|
|
|
}
|
|
|
|
*dot = '\0';
|
|
|
|
if( _stricmp( name, AnsiName ) == 0 ) {
|
|
|
|
value = TRUE;
|
|
goto exit;
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
if( hookerInfo != NULL ) {
|
|
|
|
SockDereferenceHooker( hookerInfo );
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
} // IsLocalComputerName
|
|
|