Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3309 lines
78 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:
--*/
//
// The SPI interface is UNICODE only.
//
//
// A note on the conditionals
// This source produces the winsock2 DNS RNR provider for both NT and
// Windows95. The latter is produced whem CHICAGO is defined.
// This source also produces the provider for the DNS RNR 2:1 mapper
// provider. This is produced when MAP21 is defined.
//
//
// A note on providers. This code handles NS_DNS NS_NBT and NS_HOSTS all-at-once
// If a single NS_DNS is desired to do all of these, don't define
// a provider for the others and the NS_DNS provider will consider
// NS_ALL to include the others. If, however, other providers exist,
// then the code will the explicitly correct thing. All that is needed
// is to fill in the provider IDs for NbtProviderId and LclProviderId.
#define UNICODE
#define _UNICODE
#include <winsockp.h>
#ifdef CHICAGO
#include "imported.h"
#endif
#include <tchar.h>
#include <ws2spi.h>
#include "rnrdefs.h"
#include "svcguid.h"
#include <align.h>
#include <rpc.h>
#define REGISTRY_WORKS 0 // no registry code for now
//
// Publics from RNRUTIL.C.
//
extern GUID HostnameGuid;
extern GUID AddressGuid;
extern GUID InetHostName;
extern GUID IANAGuid;
extern
DWORD
AllocateUnicodeString (
IN LPSTR lpAnsi,
IN OUT PWCHAR *lppUnicode
);
//
// Function prototypes
//
PVOID
AllocLocal(
DWORD dwSize
);
DWORD
RnRGetPortByType (
IN LPGUID lpServiceType,
IN DWORD dwType
);
INT
RnR2AddServiceType(
IN PWSASERVICECLASSINFOW psci
);
VOID
CacheHostent (
IN PHOSTENT HostEntry,
IN INT Ttl
);
PHOSTENT
QueryHostentCache (
IN LPSTR Name OPTIONAL,
IN DWORD IpAddress OPTIONAL
);
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
);
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
);
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
);
#ifndef MAP21
struct servent *
_pgetservebyport (
IN const int port,
IN const char *name
);
struct servent *
_pgetservebyname (
IN const char *name,
IN const char *proto
);
struct hostent *
_pgethostbyaddr(
IN const char *addr,
IN int len,
IN int type
);
struct hostent *
myhostent (
void
);
struct hostent *
dnshostent(
void
);
#else // MAP21
#define _pgetservebyport (*m21_getservbyport)
#define _pgetservebyname (*m21_getservbyname)
#define _pgethostbyaddr (*m21_gethostbyaddr)
#endif // MAP21
DWORD
GetServerAndProtocolsFromString(PWCHAR lpszString,
LPGUID lpType,
struct servent ** pServEnt);
#ifdef CHICAGO
#define RtlEqualMemory(x, y, z) (!memcmp(x, y, z))
#define STRICMP lstrcmpiA
#define STRLEN(s) lstrlenA(s)
#define WCSLEN lstrlenW
#define WCSCMP mywcscmp
#define WCSICMP mywcscmpi
#define WCSCPY mywcscpy
#define STRCHR mystrchr
#define STRCPY FSTRCPY
PCHAR
mystrchr(PCHAR str, CHAR c);
VOID
mywcscpy(PWCHAR src, PWCHAR dst);
DWORD
mywcscmpi(PWCHAR str1, PWCHAR str2);
DWORD
mywcscmp(PWCHAR str1, PWCHAR str2);
ULONG
SockNbtResolveName(
IN PCHAR Name
);
#else //CHICAGO
#define STRICMP _stricmp
#define STRLEN(s) strlen(s)
#define WCSLEN wcslen
#define WCSCMP wcscmp
#define WCSICMP _wcsicmp
#define WCSCPY wcscpy
#define STRCHR strchr
#define STRCPY strcpy
#endif // CHICAGO
#define GuidEqual(x,y) RtlEqualMemory(x,y, sizeof(GUID))
// Definitions and data
//
LIST_ENTRY ListAnchor = {&ListAnchor, &ListAnchor};
#define CHECKANCHORQUEUE // do queue checking on the above
#define DNS_PORT (53)
LONG lStartupCount;
#define NSP_SERVICE_KEY_NAME TEXT("SYSTEM\\CurrentControlSet\\Control\\ServiceProvider\\ServiceTypes")
DWORD MaskOfGuids;
#define DNSGUIDSEEN 0x1
#define NBTGUIDSEEN 0x2
#define LCLGUIDSEEN 0x4 // not implemented ...
//
// The provider Ids. Each of the providers implemented in this DLL
// is defined below. These match the GUIDs that setup puts in the registry.
//
GUID DNSProviderId = DNSGUID;
GUID NbtProviderId = NBTGUID;
GUID LclProviderId = LCLGUID;
#define NAME_SIZE 50
CHAR szLocalComputerName[NAME_SIZE];
PCHAR pszFullName;
#define NOPORTDEFINED (0xffffffff)
#define UDP_PORT 0 // look for the UDP port type
#define TCP_PORT 1 // look for the TCP port type
#define FreeLocal(x) FREE_HEAP(x)
#if defined(CHICAGO)
//
// On CHICAGO we define this here. On NT, it's defined in sockdata
//
CRITICAL_SECTION csRnRLock;
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif
typedef union {
HEADER hdr;
unsigned char buf[MAXPACKET];
} querybuf;
typedef union {
long al;
char ac;
} align;
LPHOSTENT
GetHostentFromName(
IN LPSOCK_THREAD pThread,
IN LPSTR Name
);
#define _gethtbyname(name) GetHostentFromName(pThread, (LPSTR)name)
LPHOSTENT
getanswer(
IN LPSOCK_THREAD pThread,
OUT querybuf * answer,
OUT LPDWORD TimeToLive,
IN int anslen,
IN int iquery
);
#ifdef UNICODE
typedef RPC_STATUS (RPC_ENTRY * LPRPCSTRINGFREE)(
IN OUT unsigned short __RPC_FAR * __RPC_FAR * String );
typedef RPC_STATUS (RPC_ENTRY * LPUUIDTOSTRING)(
IN UUID __RPC_FAR * Uuid,
OUT unsigned short __RPC_FAR * __RPC_FAR * StringUuid );
typedef RPC_STATUS (RPC_ENTRY * LPUUIDFROMSTRING)(
IN unsigned short __RPC_FAR * StringUuid,
OUT UUID __RPC_FAR * Uuid );
#define RPCSTRINGFREE_SZ "RpcStringFreeW"
#define UUIDTOSTRING_SZ "UuidToStringW"
#define UUIDFROMSTRING_SZ "UuidFromStringW"
#else // !UNICODE
typedef RPC_STATUS (RPC_ENTRY * LPRPCSTRINGFREE)(
IN OUT unsigned char __RPC_FAR * __RPC_FAR * String );
typedef RPC_STATUS (RPC_ENTRY * LPUUIDTOSTRING)(
IN UUID __RPC_FAR * Uuid,
OUT unsigned char __RPC_FAR * __RPC_FAR * StringUuid );
typedef RPC_STATUS (RPC_ENTRY * LPUUIDFROMSTRING)(
IN unsigned char __RPC_FAR * StringUuid,
OUT UUID __RPC_FAR * Uuid );
#define RPCSTRINGFREE_SZ "RpcStringFreeA"
#define UUIDTOSTRING_SZ "UuidToStringA"
#define UUIDFROMSTRING_SZ "UuidFromStringA"
#endif
static LPRPCSTRINGFREE lpRpcStringFree;
static LPUUIDTOSTRING lpUuidToString;
static LPUUIDFROMSTRING lpUuidFromString;
#else
struct hostent *
_gethtbyname (
IN char *name
);
#endif // CHICAGO
struct hostent *
localhostent();
NSP_ROUTINE nsrVector = {
sizeof(NSP_ROUTINE),
1, // major version
1, // minor version
NSPCleanup,
NSPLookupServiceBegin,
NSPLookupServiceNext,
NSPLookupServiceEnd,
NSPSetService,
NSPInstallServiceClass,
NSPRemoveServiceClass,
NSPGetServiceClassInfo
};
//
// Function Bodies
//
VOID
SaveAnswer(querybuf * query, int len, PDNS_RNR_CONTEXT pdrc)
{
if(pdrc->blAnswer.pBlobData)
{
FreeLocal(pdrc->blAnswer.pBlobData);
}
pdrc->blAnswer.cbSize = len;
pdrc->blAnswer.pBlobData = AllocLocal(len);
if(pdrc->blAnswer.pBlobData)
{
memcpy(pdrc->blAnswer.pBlobData, query->buf, len);
}
}
//
// the following three functions are used to determine which provider action
// this should honor. It allows there to be but one provider to handle all of
// the actions or distinct providers.
//
BOOL
DoDnsProvider(PDNS_RNR_CONTEXT pdrc)
{
if(GuidEqual(&pdrc->gdProviderId, &DNSProviderId))
{
return(TRUE);
}
return(FALSE);
}
BOOL
DoNbtProvider(PDNS_RNR_CONTEXT pdrc)
{
if(!pdrc->DnsRR
&&
(!(MaskOfGuids & NBTGUIDSEEN)
&&
(pdrc->dwNameSpace == NS_ALL) )
||
GuidEqual(&pdrc->gdProviderId, &NbtProviderId))
{
return(TRUE);
}
return(FALSE);
}
BOOL
DoLclProvider(PDNS_RNR_CONTEXT pdrc)
{
if(!pdrc->DnsRR
&&
(!(MaskOfGuids & LCLGUIDSEEN)
&&
(pdrc->dwNameSpace == NS_ALL) )
||
GuidEqual(&pdrc->gdProviderId, &LclProviderId))
{
return(TRUE);
}
return(FALSE);
}
//
// Get a servent for a string.
//
//
DWORD
GetServerAndProtocolsFromString(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
//
if(port)
{
sent = _pgetservebyport(port, protocolname);
}
else
{
sent = _pgetservebyname(servname, protocolname);
}
if(servname)
{
FREE_HEAP(servname);
}
if(protocolname)
{
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 = 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 = ALLOCATE_HEAP(dwLen);
if ( pszBuffer == NULL ) {
return NULL;
}
if(!WideCharToMultiByte(
CP_ACP,
0,
Name,
-1,
pszBuffer,
dwLen,
0,
0))
{
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);
}
if(pszFullName)
{
FREE_HEAP(pszFullName);
pszFullName = 0;
szLocalComputerName[0] = 0; // just in case
}
//
// If Win95, delete this now. On NT, this is done when the
// process detaches from the DLL
//
#if defined(CHICAGO)
DeleteCriticalSection(&csRnRLock);
#else
LeaveCriticalSection(&csRnRLock);
#endif
}
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;
}
}
#ifndef CHICAGO
ASSERT(Entry != &ListAnchor);
#endif
#endif
RemoveEntryList(&pdrc->ListEntry);
if(pdrc->phent)
{
FreeLocal(pdrc->phent);
}
if(pdrc->blAnswer.pBlobData)
{
FreeLocal(pdrc->blAnswer.pBlobData);
}
FreeLocal(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;
}
if(dwPort == NOPORTDEFINED)
{
//
// this was taken out because there was no time
// to test it for NT4
#if REGISTRY_WORKS
dwPort = RnRGetPortByType(lpType, dwType);
#endif
}
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];
struct servent * sent;
#ifdef CHICAGO
LPSOCK_THREAD pThread;
#endif
if(!SockEnterApi(FALSE, TRUE, TRUE))
{
return(SOCKET_ERROR);
}
if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW))
{
SetLastError(WSAEFAULT);
return(SOCKET_ERROR);
}
if(!lpqsRestrictions->lpServiceClassId)
{
//
// gotta have a class ID.
//
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
//
SetLastError(WSANO_DATA);
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))
{
return(SOCKET_ERROR);
}
}
else
{
badparm:
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(!pszAnsiName)
{
//
// if out of memory, give up now
//
SetLastError(WSA_NOT_ENOUGH_MEMORY);
return(SOCKET_ERROR);
}
if(!STRICMP(pszAnsiName, "localhost")
||
!STRICMP(pszAnsiName, "loopback"))
{
dwLocalFlags |= LOCALLOOK | LOOPLOOK;
}
else if(!STRICMP(pszAnsiName, szLocalComputerName)
||
!STRICMP(pszAnsiName, pszFullName))
{
dwLocalFlags |= LOCALLOOK;
}
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?
//
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(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
{
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)
{
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;
WCSCPY(pdrc->wcName, pwszServiceName);
RnR2ReleaseContext(pdrc);
*lphLookup = (HANDLE)pdrc;
//
// If necessary, compute the DNS lookup type
//
if(IS_SVCID_TCP(lpqsRestrictions->lpServiceClassId)
||
IS_SVCID_UDP(lpqsRestrictions->lpServiceClassId))
{
pdrc->DnsRR = RR_FROM_SVCID(lpqsRestrictions->lpServiceClassId);
//
// BUGBUG. Should a query value of T_A be ignored? Note that
// specifying T_A will cause all of the local optimizations
// to be bypassed. Hence, it seems as if it is a good idea
// to ingnore it. What is the harm?
//
if(pdrc->DnsRR == T_A)
{
pdrc->DnsRR = 0;
}
}
if (dwControlFlags & LUP_FLUSHCACHE) {
_res.options &= ~RES_INIT;
//
// BUGBUG. Implement this...
//
// FlushHostentCache();
}
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
--*/
DWORD err = NO_ERROR;
PDNS_RNR_CONTEXT pdrc;
PBYTE pData = (PBYTE)(lpqsResults + 1);
LONG lSpare = (LONG)*lpdwBufferLength - lpqsResults->dwSize;
LPSTR pAnsiName = 0;
querybuf queryBuffer;
PHOSTENT hostEntry = 0;
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 = 0;
CHAR szComputerName[20];
BOOL fHaveGlobalLock = FALSE;
#ifdef CHICAGO
LPSOCK_THREAD pThread;
#endif
if(!SockEnterApi(FALSE, TRUE, TRUE))
{
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);
#if 0 // don't append domain name as it breaks
// apps using DNS as a WINS wrapper. Lame!
//
#ifndef MAP21 // never append domain in the 2:1 mapper
if(pdrc->fFlags & NEEDDOMAIN)
{
phe = myhostent();
if(!phe)
{
//
// this has actually happened, believe it or not!
//
err = GetLastError();
goto Done;
}
pszDomain = STRCHR(phe->h_name, '.');
}
else
#endif // ifndef MAP21
#endif
{
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->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);
#ifndef MAP21
hostEntry = _pgethostbyaddr((PCHAR)&dwIp,
4,
AF_INET);
#else // MAP21
hostEntry = (*ws21_gethostbyaddr)((PCHAR)&dwIp,
4,
AF_INET);
#endif // MAP21
}
else if(pdrc->DnsRR || !(pdrc->fFlags & LOCALLOOK))
{
//
// a real name lookup. See which provider type to use
//
#ifndef MAP21 // if we have to do it ...
INT count, ttl;
PCHAR pszName = *pAnsiName ? pAnsiName : pszFullName;
if(DoLclProvider(pdrc))
{
//
// Always try the local database first.
//
hostEntry = _gethtbyname(pszName);
}
if(!hostEntry && DoDnsProvider(pdrc))
{
//
// Not in the local hosts file. See if DNS
// knows about it
//
SockAcquireGlobalLockExclusive();
if(!pdrc->DnsRR)
{
hostEntry = QueryHostentCache(pszName, 0);
}
if(!hostEntry)
{
//
// it's not in the cache. Go looking for it.
//
SockReleaseGlobalLock();
if((res_init() != -1))
{
//
// must try DNS
count = res_search(pAnsiName,
C_IN,
pdrc->DnsRR ? pdrc->DnsRR : T_A,
queryBuffer.buf,
sizeof(queryBuffer));
if ( count >= 0 )
{
if(pdrc->DnsRR)
{
SaveAnswer(&queryBuffer, count, pdrc);
}
#if defined(CHICAGO)
hostEntry = getanswer(
pThread,
&queryBuffer,
&ttl,
count,
0);
#else // CHICAGO
hostEntry = getanswer(
&queryBuffer,
&ttl,
count,
0);
#endif // CHICAGO
if(hostEntry)
{
if(!pdrc->DnsRR)
{
CacheHostent(hostEntry, ttl);
}
}
else if(pdrc->blAnswer.pBlobData
&&
(pdrc->dwControlFlags & LUP_RETURN_BLOB)
)
{
//
// getanswer failed, but the caller
// wants the raw answer. So only
// return that, but also conjure
// a valid hostEntry for later on
//
pdrc->dwControlFlags &= LUP_RETURN_BLOB;
hostEntry = myhostent();
}
}
}
}
else
{
//
// remember we got this from the cache and
// hold the lock until we can copy the data.
//
fHaveGlobalLock = TRUE;
}
}
if(!hostEntry)
{
//
// DNS didn't find it. See if NBT can find it
//
if(DoNbtProvider(pdrc))
{
LocalAddress = SockNbtResolveName(pAnsiName);
if(LocalAddress != INADDR_NONE)
{
//
// WINS found it.
//
// Make up a host entry that has one address.
//
hostEntry = &LocalHostEntry;
hostEntry->h_name = pAnsiName;
hostEntry->h_aliases = 0;
hostEntry->h_addr_list = (PCHAR *)local_addr_list;
local_addr_list[0] = &LocalAddress;
local_addr_list[1] = 0;
hostEntry->h_addrtype = AF_INET;
hostEntry->h_length = sizeof(ULONG);
}
}
}
#else // MAP21
//
// if in the 2:1 mapper, just defer the call to
// someone else.
//
hostEntry = (*m21_gethostbyname)(pAnsiName);
#endif // MAP21
}
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
//
#ifndef MAP21
if(pdrc->fFlags & LOOPLOOK)
{
hostEntry = localhostent();
}
else
{
#if DNSADDRESSHACK
//
// if enabled, this code will return the machine's
// DNS addresses when the lookup is on a NULL name
// and the port is the DNS port.
//
if(!*pAnsiName
&&
((pdrc->dwUdpPort == DNS_PORT)
||
(pdrc->dwTcpPort == DNS_PORT)) )
{
//
// special DNS address-list hack
//
hostEntry = dnshostent();
if(hostEntry)
{
hostEntry->h_name = szLocalComputerName;
}
}
else
{
hostEntry = myhostent();
}
#else // DNSADDRESSHACK
hostEntry = myhostent();
#endif // DNSADDRESSHACK
if(hostEntry)
{
if(!*pAnsiName)
{
PCHAR pszDot;
//
// this is a gethostbyname. So return
// the machine name part only. Do
// this by copying the machine-name
// prefix to a local. It really doesn't
// matter since just below the
// hostEntry is copied and saved in the
// lookup context so we don't care
// about what we got back from myhostent.
//
pszDot = STRCHR(hostEntry->h_name, '.');
if(pszDot)
{
DWORD dwDot = pszDot - hostEntry->h_name;
memcpy(szComputerName,
hostEntry->h_name,
dwDot);
szComputerName[dwDot] = 0;
hostEntry->h_name = szComputerName;
}
}
}
}
#else // MAP21
CHAR szLocalHostName[1000]; // 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.
//
if(!(*m21_ghethostname(szLocalHost, 1000)))
{
hostEntry = (*m21_gethostbyname(szLocalHostName);
}
#endif // MAP21
}
if(hostEntry)
{
LONG lSizeOf;
//
// 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;
//
// if this is from the hostent cache, free the lock now
//
if(fHaveGlobalLock)
{
SockReleaseGlobalLock();
fHaveGlobalLock = FALSE; // keep things neat.
}
}
}
if(!hostEntry)
{
err = GetLastError();
if(err == NO_ERROR)
{
err = WSASERVICE_NOT_FOUND;
}
goto Done;
}
//
// 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;
}
else if(pdrc->DnsRR && pdrc->blAnswer.pBlobData)
{
LONG lLen = sizeof(BLOB) + pdrc->blAnswer.cbSize;
//
// return the raw answer, if it fits
//
lFree -= lLen;
if(lFree >= 0)
{
lpqsResults->lpBlob = (LPBLOB)pBuff;
pBuff += lLen;
lpqsResults->lpBlob->pBlobData = pBuff;
lpqsResults->lpBlob->cbSize = pdrc->blAnswer.cbSize;
memcpy(pBuff,
pdrc->blAnswer.pBlobData,
pdrc->blAnswer.cbSize);
}
else
{
err = WSAEFAULT;
}
}
}
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;
}
FREE_HEAP(pszString);
}
Done:
if(pAnsiName)
{
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;
pdrc = RnR2GetContext(hLookup);
if(!pdrc)
{
SetLastError(WSA_INVALID_HANDLE);
return(SOCKET_ERROR);
}
pdrc->fFlags |= DNS_F_END_CALLED;
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
)
{
return(NO_ERROR);
}
INT WINAPI
NSPCleanup(
IN LPGUID lpProviderId
)
{
if(!InterlockedDecrement(&lStartupCount))
{
RnR2Cleanup(); // zap all contexts
}
// WSACleanup();
return(NO_ERROR);
}
INT WINAPI
NSPSetService(
IN LPGUID lpProviderId,
IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
IN LPWSAQUERYSETW lpqsRegInfo,
IN WSAESETSERVICEOP essOperation,
IN DWORD dwControlFlags
)
{
/*++
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
)
{
/*++
Must be done manually
--*/
//
// This was taken out because there was no time to test
// it for NT4.
//
#if REGISTRY_WORKS
return(RnR2AddServiceType(lpServiceClassInfo));
#else
return(NO_ERROR);
#endif
}
INT WINAPI
NSPRemoveServiceClass(
IN LPGUID lpProviderId,
IN LPGUID lpServiceCallId
)
{
return(NO_ERROR);
}
INT WINAPI
NSPGetServiceClassInfo(
IN LPGUID lpProviderId,
IN OUT LPDWORD lpdwBufSize,
IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo
)
{
/*++
Routine Description:
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);
#ifdef CHICAGO
LPSOCK_THREAD pThread;
BOOL DemandLoadRpcrt4();
#endif
//
// BUGBUG. If no size is provided, assume it is big enough!!!!
//
// WSAStartup(2, &wsaData);
if(!SockEnterApi(FALSE, TRUE, TRUE))
{
return(SOCKET_ERROR);
}
InterlockedIncrement(&lStartupCount);
if(!szLocalComputerName[0])
{
struct hostent * myent = myhostent();
PCHAR pszDot, pszDest;
DWORD dwLen;
//
// Get the computer name and stash it for comparison.
//
if(!myent)
{
Error:
//
// if we can't get the local computer name or
// the local host entry, something is very amiss
// and we should refuse to load.
//
if(!GetLastError())
{
//
// insure there is an error to examine
//
SetLastError(WSASYSNOTREADY);
}
return(SOCKET_ERROR);
}
//
// save it
//
dwLen = strlen(myent->h_name) + 1;
pszFullName = (PCHAR)ALLOCATE_HEAP(dwLen);
if(!pszFullName)
{
goto Error;
}
memcpy(pszFullName, myent->h_name, dwLen);
//
// Now compute the name without the domain suffix.
//
pszDot = pszFullName;
pszDest = szLocalComputerName;
while(*pszDot && (*pszDot != '.'))
{
*pszDest++ = *pszDot++;
}
}
if(!dwSize)
{
dwSize = sizeof(nsrVector);
}
RtlCopyMemory(lpsnpRoutines,
&nsrVector,
dwSize);
if(GuidEqual(lpProviderId, &NbtProviderId))
{
MaskOfGuids |= NBTGUIDSEEN;
}
else if(GuidEqual(lpProviderId, &LclProviderId))
{
MaskOfGuids |= LCLGUIDSEEN;
}
else
{
MaskOfGuids |= DNSGUIDSEEN;
DNSProviderId = *lpProviderId; // save it
}
#ifdef CHICAGO
DemandLoadRpcrt4();
#endif
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);
}
//
// The following is not used, but is here. It was implemented for NT 4
// but too late to make it into the release.
//
#if REGISTRY_WORKS
INT
RnRGetTypeByName (
IN LPTSTR lpServiceName,
IN OUT LPGUID lpServiceType
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
INT err;
HKEY serviceTypesKey;
HKEY serviceKey;
TCHAR guidString[100];
DWORD length;
DWORD type;
//
// Open the key that stores the name space provider info.
//
err = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
NSP_SERVICE_KEY_NAME,
0,
KEY_READ,
&serviceTypesKey
);
if ( err == NO_ERROR ) {
//
// Open the key for this particular service.
//
err = RegOpenKeyEx(
serviceTypesKey,
lpServiceName,
0,
KEY_READ,
&serviceKey
);
RegCloseKey( serviceTypesKey );
//
// If the key exists then we will read the GUID from the registry.
//
if ( err == NO_ERROR ) {
//
// Query the GUID value for the service.
//
length = sizeof(guidString);
err = RegQueryValueEx(
serviceKey,
TEXT("GUID"),
NULL,
&type,
(PVOID)guidString,
&length
);
RegCloseKey( serviceKey );
if ( err != NO_ERROR ) {
SetLastError( err );
return -1;
}
//
// Convert the Guid string to a proper Guid representation.
// Before calling the conversion routine, we must strip the
// leading and trailing braces from the string.
//
guidString[_tcslen(guidString) - 1] = L'\0';
#ifndef CHICAGO
err = UuidFromString(
#else
err = lpUuidFromString(
#endif
guidString + 1, lpServiceType );
if ( err != NO_ERROR ) {
SetLastError( err );
return -1;
}
return NO_ERROR;
}
}
return -1;
} //RnR GetTypeByName
DWORD
RnRGetPortByType (
IN LPGUID lpServiceType,
IN DWORD dwType
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
INT err;
HKEY serviceTypesKey;
DWORD keyIndex;
TCHAR serviceName[255];
DWORD nameLength;
FILETIME lastWriteTime;
GUID guid;
//
// Open the key that stores the name space provider info.
//
err = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
NSP_SERVICE_KEY_NAME,
0,
KEY_READ,
&serviceTypesKey
);
if ( err == NO_ERROR ) {
//
// Walk through the service keys, checking whether each one
// corresponds to the Guid we're checking against.
//
keyIndex = 0;
nameLength = sizeof(serviceName);
while ( (err = RegEnumKeyEx(
serviceTypesKey,
keyIndex,
serviceName,
&nameLength,
NULL,
NULL,
NULL,
&lastWriteTime) == NO_ERROR ) ) {
//
// Get the Guid for this service type. This is pretty lazy
// but it makes it modular
//
err = RnRGetTypeByName( serviceName, &guid );
if ( err == NO_ERROR ) {
//
// Check whether this Guid matches the one we're looking for.
//
if ( GuidEqual( lpServiceType, &guid ) ) {
HKEY key1;
DWORD length = sizeof(DWORD);
DWORD dwPort;
//
// We have a match. See if we can find the
// desired port
//
err = RegOpenKeyEx(
serviceTypesKey,
serviceName,
0,
KEY_READ,
&key1
);
RegCloseKey( serviceTypesKey );
if(err == NO_ERROR)
{
LPTSTR pwszValue;
DWORD type;
if(dwType == UDP_PORT)
{
pwszValue = SERVICE_TYPE_VALUE_UDPPORT;
}
else
{
pwszValue = SERVICE_TYPE_VALUE_TCPPORT;
}
err = RegQueryValueEx(
key1,
pwszValue,
NULL,
&type,
(PVOID)&dwPort,
&length
);
RegCloseKey(key1);
if(err == NO_ERROR)
{
return dwPort;
}
}
return(NOPORTDEFINED); // not here.
}
}
//
// Update locals for the next call to RegEnumKeyEx.
//
keyIndex++;
nameLength = sizeof(serviceName);
}
RegCloseKey( serviceTypesKey );
}
return NOPORTDEFINED;
} // GetNameByType
//
// Worker to add ClassInfo
//
INT
RnR2AddServiceType(
IN PWSASERVICECLASSINFOW psci
)
{
HKEY hKey, hKeyService;
LPTSTR pwszUuid;
INT err;
DWORD dwDisposition;
TCHAR wszUuid[36 + 1 + 2]; // to hold the GUID
#ifdef CHICAGO
LPSTR pAnsiString;
#endif
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
NSP_SERVICE_KEY_NAME,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hKey,
&dwDisposition );
if(err)
{
return(SOCKET_ERROR);
}
//
// Open the key corresponding to the service (create if not there).
//
#ifdef CHICAGO
pAnsiString = GetAnsiNameRnR(psci->lpszServiceClassName, 0);
if(pAnsiString)
{
#endif
err = RegCreateKeyEx(
hKey,
#ifndef CHICAGO
psci->lpszServiceClassName,
#else
pAnsiString,
#endif
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hKeyService,
&dwDisposition
);
#ifdef CHICAGO
FREE_HEAP(pAnsiString);
}
else
{
err = GetLastError();
}
#endif
if(!err)
{
//
// ready to put the GUID value in.
//
#ifdef CHICAGO
lpUuidToString(
#else
UuidToString(
#endif
psci->lpServiceClassId,
&pwszUuid);
wszUuid[0] = TEXT('{');
memcpy(&wszUuid[1], pwszUuid, 36 * sizeof(TCHAR));
wszUuid[37] = TEXT('}');
wszUuid[38] = 0;
#ifndef CHICAGO
RpcStringFree(&pwszUuid);
#else
lpRpcStringFree(&pwszUuid);
#endif
//
// write it
err = RegSetValueEx(
hKeyService,
TEXT("GUID"),
0,
REG_SZ,
(LPBYTE)wszUuid,
39 * sizeof(TCHAR));
if(!err)
{
//
// add the appropriate items from the Class Info structures
PWSANSCLASSINFOW pci = psci->lpClassInfos;
DWORD dwCount = psci->dwCount;
while(dwCount--)
{
if(pci->dwNameSpace == NS_DNS)
{
//
// it's ours
//
#ifdef CHICAGO
pAnsiString = GetAnsiNameRnR(pci->lpszName, 0);
if(pAnsiString)
{
#endif
err = RegSetValueEx(
hKeyService,
#ifndef CHICAGO
pci->lpszName,
#else
pAnsiString,
#endif
0,
pci->dwValueType,
(LPBYTE)pci->lpValue,
pci->dwValueSize);
#ifdef CHICAGO
FREE_HEAP(pAnsiString);
}
else
{
err = GetLastError();
}
#endif
if(err)
{
break;
}
}
pci++;
}
}
RegCloseKey(hKeyService);
}
RegCloseKey(hKey);
if(err)
{
err = SOCKET_ERROR;
}
return(err);
}
#endif // if REGISTRY_WORKS. Code not included in NT4 because of time
//
// If WIN95, include these functions to avoid invoking the C runtime.
// Why strchr is not an intrinsic is a mystery to me, but so is a lot
// of WIN95.
//
#if defined(CHICAGO)
PWCHAR
wcschr(const wchar_t * wstr, WCHAR b)
{
PWCHAR a = (PWCHAR)wstr;
while(*a != b)
{
if(!*a)
{
a = 0;
break;
}
a++;
}
return(a);
}
PCHAR
mystrchr(PCHAR str, CHAR b)
{
PCHAR a = (PCHAR)str;
while(*a != b)
{
if(!*a)
{
a = 0;
break;
}
a++;
}
return(a);
}
VOID
mywcscpy(PWCHAR src, PWCHAR dst)
{
while(*src++ = *dst++)
;
}
DWORD
mywcscmp(PWCHAR str1, PWCHAR str2)
{
while(1)
{
if(*str1 == *str2)
{
if(!*str1)
{
return(0);
}
str1++;
str2++;
}
else
{
return(1);
}
}
}
DWORD
mywcscmpi(PWCHAR str1, PWCHAR str2)
{
LPSTR psz1;
LPSTR psz2;
DWORD rc;
psz1 = GetAnsiNameRnR(str1, 0);
psz2 = GetAnsiNameRnR(str2, 0);
if(psz1 && psz2)
{
rc = STRICMP(psz1, psz2);
}
else
{
rc = 1;
}
if(psz1)
{
FREE_HEAP(psz1);
}
if(psz2)
{
FREE_HEAP(psz2);
}
return(rc);
}
static HINSTANCE hRpcrt4Dll = NULL;
static LPRPCSTRINGFREE lpRpcStringFree = NULL;
static LPUUIDTOSTRING lpUuidToString = NULL;
static LPUUIDFROMSTRING lpUuidFromString = NULL;
static
BOOL
DemandLoadRpcrt4(
VOID
)
{
//
// Load RPCRT4.DLL if not already loaded.
//
if( hRpcrt4Dll == NULL )
{
hRpcrt4Dll = LoadLibrary( TEXT("RPCRT4.DLL") );
}
//
// If loaded, find the entrypoints.
//
if( ( hRpcrt4Dll != NULL ) &&
( lpRpcStringFree == NULL ) &&
( lpUuidToString == NULL ) &&
( lpUuidFromString == NULL ) )
{
lpRpcStringFree = (LPRPCSTRINGFREE)GetProcAddress( hRpcrt4Dll,
RPCSTRINGFREE_SZ );
lpUuidToString = (LPUUIDTOSTRING)GetProcAddress( hRpcrt4Dll,
UUIDTOSTRING_SZ );
lpUuidFromString = (LPUUIDFROMSTRING)GetProcAddress( hRpcrt4Dll,
UUIDFROMSTRING_SZ )
;
}
//
// Return TRUE if RPCRT4.DLL loaded and all entrypoints found.
//
return ( lpRpcStringFree != NULL ) &&
( lpUuidToString != NULL ) &&
( lpUuidFromString != NULL );
} // DemandLoadRpcrt4
#endif