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.
3309 lines
78 KiB
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
|