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.
1767 lines
42 KiB
1767 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gethost.c
|
|
|
|
Abstract:
|
|
|
|
This module implements hostname -> IP address resolution routines.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
/******************************************************************
|
|
*
|
|
* SpiderTCP BIND
|
|
*
|
|
* Copyright 1990 Spider Systems Limited
|
|
*
|
|
* GETHOST.C
|
|
*
|
|
******************************************************************/
|
|
|
|
/*
|
|
* /usr/projects/tcp/SCCS.rel3/rel/src/lib/net/0/s.gethost.c
|
|
* @(#)gethost.c 5.3
|
|
*
|
|
* Last delta created 14:09:38 3/4/91
|
|
* This file extracted 11:20:08 3/8/91
|
|
*
|
|
* Modifications:
|
|
*
|
|
* GSS 24 Jul 90 New File
|
|
*/
|
|
/*
|
|
* Copyright (c) 1985, 1988 Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that the above copyright notice and this paragraph are
|
|
* duplicated in all such forms and that any documentation,
|
|
* advertising materials, and other materials related to such
|
|
* distribution and use acknowledge that the software was developed
|
|
* by the University of California, Berkeley. The name of the
|
|
* University may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char sccsid[] = "@(#)gethostnamadr.c 6.39 (Berkeley) 1/4/90";
|
|
#endif /* LIBC_SCCS and not lint */
|
|
/***************************************************************************/
|
|
|
|
#include "winsockp.h"
|
|
#include <nbtioctl.h>
|
|
#include <nb30.h>
|
|
#include <nspapi.h>
|
|
#include <svcguid.h>
|
|
#include <nspmisc.h>
|
|
|
|
extern GUID HostnameGuid;
|
|
|
|
#define h_addr_ptrs ACCESS_THREAD_DATA( h_addr_ptrs, GETHOST )
|
|
#define host ACCESS_THREAD_DATA( host, GETHOST )
|
|
#define host_aliases ACCESS_THREAD_DATA( host_aliases, GETHOST )
|
|
#define hostbuf ACCESS_THREAD_DATA( hostbuf, GETHOST )
|
|
#define host_addr ACCESS_THREAD_DATA( host_addr, GETHOST )
|
|
#define HOSTDB ACCESS_THREAD_DATA( HOSTDB, GETHOST )
|
|
#define hostf ACCESS_THREAD_DATA( hostf, GETHOST )
|
|
#define hostaddr ACCESS_THREAD_DATA( hostaddr, GETHOST )
|
|
#define host_addrs ACCESS_THREAD_DATA( host_addrs, GETHOST )
|
|
#define stayopen ACCESS_THREAD_DATA( stayopen, GETHOST )
|
|
|
|
char TCPIPLINK[] = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Linkage";
|
|
char TCPLINK[] = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcp\\Linkage";
|
|
char REGBASE[] = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
|
|
|
//
|
|
// Globals for caching open NBT control channel handles. See the description
|
|
// of SockOpenNbt() for details.
|
|
//
|
|
|
|
DWORD SockNbtHandleCount = 0;
|
|
PHANDLE SockNbtHandles = NULL;
|
|
PHANDLE SockSparseNbtHandles = NULL;
|
|
DWORD SockNbtDeviceCount = 0;
|
|
PWSTR SockNbtDeviceNames = NULL;
|
|
BOOLEAN SockNbtFullyInitialized = FALSE;
|
|
|
|
BOOL
|
|
SockNbtResolveAddr (
|
|
IN ULONG IpAddr,
|
|
IN PCHAR Name
|
|
);
|
|
|
|
DWORD
|
|
SockOpenNbt (
|
|
VOID
|
|
);
|
|
|
|
struct hostent *
|
|
_pgethostbyaddr(
|
|
IN const char *addr,
|
|
IN int len,
|
|
IN int type
|
|
);
|
|
|
|
int
|
|
_pgethostname(
|
|
OUT char * addr,
|
|
IN int len
|
|
);
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ADAPTER_STATUS AdapterInfo;
|
|
NAME_BUFFER Names[32];
|
|
} tADAPTERSTATUS;
|
|
|
|
|
|
struct hostent *
|
|
getanswer(
|
|
OUT querybuf *answer,
|
|
OUT int *ttl,
|
|
IN int anslen,
|
|
IN int iquery
|
|
)
|
|
{
|
|
register HEADER *hp;
|
|
register unsigned char *cp;
|
|
register int n;
|
|
unsigned char *eom;
|
|
char *bp, **ap;
|
|
int type, class, buflen, ancount, qdcount;
|
|
int haveanswer, getclass = C_ANY;
|
|
char **hap;
|
|
|
|
*ttl = 0x7fffffff;
|
|
|
|
eom = answer->buf + anslen;
|
|
/*
|
|
* find first satisfactory answer
|
|
*/
|
|
hp = &answer->hdr;
|
|
ancount = ntohs(hp->ancount);
|
|
ancount = min( ancount, MAXADDRS );
|
|
qdcount = ntohs(hp->qdcount);
|
|
bp = hostbuf;
|
|
buflen = BUFSIZ+1;
|
|
cp = answer->buf + sizeof(HEADER);
|
|
|
|
if (qdcount) {
|
|
|
|
if (iquery) {
|
|
|
|
if ((n = dn_expand((char *)answer->buf, eom,
|
|
cp, bp, buflen)) < 0) {
|
|
SetLastError(WSANO_RECOVERY);
|
|
return ((struct hostent *) NULL);
|
|
}
|
|
|
|
cp += n + QFIXEDSZ;
|
|
host.h_name = bp;
|
|
n = strlen(bp) + 1;
|
|
bp += n;
|
|
buflen -= n;
|
|
|
|
} else {
|
|
|
|
cp += dn_skipname(cp, eom) + QFIXEDSZ;
|
|
}
|
|
|
|
while (--qdcount > 0) {
|
|
cp += dn_skipname(cp, eom) + QFIXEDSZ;
|
|
}
|
|
|
|
} else if (iquery) {
|
|
|
|
if (hp->aa) {
|
|
SetLastError(HOST_NOT_FOUND);
|
|
} else {
|
|
SetLastError(TRY_AGAIN);
|
|
}
|
|
|
|
return ((struct hostent *) NULL);
|
|
}
|
|
|
|
ap = host_aliases;
|
|
*ap = NULL;
|
|
host.h_aliases = host_aliases;
|
|
hap = h_addr_ptrs;
|
|
*hap = NULL;
|
|
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
|
|
host.h_addr_list = h_addr_ptrs;
|
|
#endif
|
|
haveanswer = 0;
|
|
|
|
while (--ancount >= 0 && cp < eom) {
|
|
|
|
if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0) {
|
|
break;
|
|
}
|
|
|
|
cp += n;
|
|
type = _getshort(cp);
|
|
cp += sizeof(USHORT);
|
|
class = _getshort(cp);
|
|
cp += sizeof(unsigned short);
|
|
|
|
n = _getlong(cp);
|
|
if (n < *ttl) {
|
|
*ttl = n;
|
|
}
|
|
|
|
cp += sizeof(unsigned long);
|
|
n = _getshort(cp);
|
|
cp += sizeof(u_short);
|
|
|
|
if (type == T_CNAME) {
|
|
cp += n;
|
|
if (ap >= &host_aliases[MAXALIASES-1]) {
|
|
continue;
|
|
}
|
|
*ap++ = bp;
|
|
n = strlen(bp) + 1;
|
|
bp += n;
|
|
buflen -= n;
|
|
continue;
|
|
}
|
|
|
|
if (iquery && type == T_PTR) {
|
|
if ((n = dn_expand((char *)answer->buf, eom,
|
|
cp, bp, buflen)) < 0) {
|
|
cp += n;
|
|
continue;
|
|
}
|
|
cp += n;
|
|
host.h_name = bp;
|
|
return(&host);
|
|
}
|
|
|
|
if (iquery || type != T_A) {
|
|
IF_DEBUG(RESOLVER) {
|
|
WS_PRINT(("unexpected answer type %d, size %d\n",
|
|
type, n));
|
|
}
|
|
cp += n;
|
|
continue;
|
|
}
|
|
if (haveanswer) {
|
|
if (n != host.h_length) {
|
|
cp += n;
|
|
continue;
|
|
}
|
|
if (class != getclass) {
|
|
cp += n;
|
|
continue;
|
|
}
|
|
} else {
|
|
host.h_length = n;
|
|
getclass = class;
|
|
host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
|
|
if (!iquery) {
|
|
host.h_name = bp;
|
|
bp += strlen(bp) + 1;
|
|
}
|
|
}
|
|
|
|
bp += sizeof(align) - ((unsigned long)bp % sizeof(align));
|
|
|
|
if (bp + n >= &hostbuf[BUFSIZ+1]) {
|
|
IF_DEBUG(RESOLVER) {
|
|
WS_PRINT(("size (%d) too big\n", n));
|
|
}
|
|
break;
|
|
}
|
|
bcopy(cp, *hap++ = bp, n);
|
|
bp +=n;
|
|
cp += n;
|
|
haveanswer++;
|
|
}
|
|
|
|
host.h_length = sizeof(unsigned long);
|
|
|
|
if (haveanswer) {
|
|
*ap = NULL;
|
|
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
|
|
*hap = NULL;
|
|
#else
|
|
host.h_addr = h_addr_ptrs[0];
|
|
#endif
|
|
return (&host);
|
|
} else {
|
|
SetLastError(TRY_AGAIN);
|
|
return ((struct hostent *) NULL);
|
|
}
|
|
}
|
|
|
|
|
|
struct hostent *
|
|
_pgethostbyaddr(
|
|
IN const char *addr,
|
|
IN int len,
|
|
IN int type
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Internal form of above
|
|
--*/
|
|
{
|
|
int n;
|
|
querybuf buf;
|
|
register struct hostent *hp;
|
|
char qbuf[MAXDNAME];
|
|
extern struct hostent *_gethtbyaddr();
|
|
int ttl;
|
|
PHOSTENT hostEntry;
|
|
char *bp;
|
|
int index;
|
|
|
|
WS_ENTER( "GETXBYYSP_gethostbyaddr", (PVOID)addr, (PVOID)len, (PVOID)type, NULL );
|
|
|
|
if ( !SockEnterApi( FALSE, TRUE, TRUE ) ) {
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", 0, TRUE );
|
|
return NULL;
|
|
}
|
|
|
|
if (type != AF_INET) {
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
SetLastError(WSANO_RECOVERY);
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", 0, TRUE );
|
|
return ((struct hostent *) NULL);
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
//
|
|
// The following code is #ifdef'd out so that gethostbyaddr *never*
|
|
// uses the hostent cache. Performing a hostent cache lookup for
|
|
// reverse name resolution can return wrong/incomplete data,
|
|
// especially for multihomed machines. We never cache the results of
|
|
// a reverse name resolution, so we should not reference the cache
|
|
// either.
|
|
//
|
|
// -- keithmo, 29-Feb-1996 (happy leap year!)
|
|
//
|
|
|
|
//
|
|
// First look in the hostent cache. We hold the hostent cache lock
|
|
// until we're completely done with any returned hostent. This
|
|
// prevents another thread from screwing with the list or the
|
|
// returned hostent while we're processing.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
|
|
//
|
|
// Attempt to find the name in the hostent cache.
|
|
//
|
|
|
|
hostEntry = QueryHostentCache( NULL, *(PDWORD)addr );
|
|
|
|
//
|
|
// If we found it, copy it to the user host structure and return.
|
|
//
|
|
|
|
if ( hostEntry != NULL ) {
|
|
|
|
host.h_addr_list = h_addr_ptrs;
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
host.h_aliases = host_aliases;
|
|
|
|
//
|
|
// Copy over the IP addresses for the host.
|
|
//
|
|
|
|
bp = hostbuf;
|
|
|
|
for ( index = 0;
|
|
hostEntry->h_addr_list[index] != NULL &&
|
|
(DWORD)bp - (DWORD)hostbuf < BUFSIZ;
|
|
index++ ) {
|
|
|
|
host.h_addr_list[index] = bp;
|
|
bp += 4;
|
|
*((long *)host.h_addr_list[index]) =
|
|
*((long *)hostEntry->h_addr_list[index]);
|
|
}
|
|
|
|
host.h_addr_list[index] = NULL;
|
|
|
|
//
|
|
// Copy over the host's aliases.
|
|
//
|
|
|
|
for ( index = 0;
|
|
hostEntry->h_aliases[index] != NULL &&
|
|
(DWORD)bp - (DWORD)hostbuf < BUFSIZ;
|
|
index++ ) {
|
|
|
|
host.h_aliases[index] = bp;
|
|
bp += strlen( hostEntry->h_aliases[index] ) + 1;
|
|
strcpy( host.h_aliases[index], hostEntry->h_aliases[index] );
|
|
}
|
|
|
|
host.h_aliases[index] = NULL;
|
|
|
|
strcpy( bp, hostEntry->h_name );
|
|
host.h_name = bp;
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", 0, TRUE );
|
|
|
|
return &host;
|
|
}
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
//
|
|
// End of #ifdef'd out hostent cache stuff.
|
|
//
|
|
// -- keithmo, 29-Feb-1996 (happy leap year!)
|
|
//
|
|
|
|
#endif
|
|
|
|
(void)wsprintfA(qbuf, "%u.%u.%u.%u.in-addr.arpa",
|
|
((unsigned)addr[3] & 0xff),
|
|
((unsigned)addr[2] & 0xff),
|
|
((unsigned)addr[1] & 0xff),
|
|
((unsigned)addr[0] & 0xff));
|
|
|
|
//
|
|
// Next, try the hosts file.
|
|
//
|
|
|
|
IF_DEBUG(GETXBYY) {
|
|
WS_PRINT(("GETXBYYSP_gethostbyaddr trying HOST\n"));
|
|
}
|
|
hp = _gethtbyaddr(addr, len, type);
|
|
if (hp != NULL) {
|
|
IF_DEBUG(GETXBYY) {
|
|
WS_PRINT(("GETXBYYSP_gethostbyaddr HOST successful\n"));
|
|
}
|
|
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", (INT)hp, FALSE );
|
|
return (hp);
|
|
}
|
|
|
|
//
|
|
// Initialize the DNS.
|
|
//
|
|
|
|
if (res_init() != -1) {
|
|
|
|
//
|
|
// Now query DNS for the information.
|
|
//
|
|
|
|
IF_DEBUG(RESOLVER) {
|
|
WS_PRINT(("GETXBYYSP_gethostbyaddr trying DNS\n"));
|
|
}
|
|
if ((n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf))) >= 0) {
|
|
hp = getanswer(&buf, &ttl, n, 1);
|
|
if (hp != NULL) {
|
|
IF_DEBUG(GETXBYY) {
|
|
WS_PRINT(("GETXBYYSP_gethostbyaddr DNS successful\n"));
|
|
}
|
|
hp->h_addrtype = type;
|
|
hp->h_length = len;
|
|
h_addr_ptrs[0] = (char *)&host_addr;
|
|
h_addr_ptrs[1] = (char *)0;
|
|
host_addr = *(struct in_addr *)addr;
|
|
#if BSD < 43 && !defined(h_addr) /* new-style hostent structure */
|
|
hp->h_addr = h_addr_ptrs[0];
|
|
#endif
|
|
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", (INT)hp, FALSE );
|
|
return(hp);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// As a last attempt, try NBT.
|
|
//
|
|
|
|
if ( SockNbtResolveAddr( *(PULONG)addr, &hostbuf[0] ) ) {
|
|
|
|
host.h_addr_list = h_addr_ptrs;
|
|
host.h_addr = hostaddr;
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
*(PDWORD)host.h_addr_list[0] = *(PULONG)addr;
|
|
|
|
host.h_name = &hostbuf[0];
|
|
*host_aliases = NULL;
|
|
host.h_aliases = host_aliases;
|
|
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", 0, TRUE );
|
|
|
|
return (&host);
|
|
}
|
|
|
|
IF_DEBUG(GETXBYY) {
|
|
WS_PRINT(("GETXBYYSP_gethostbyaddr unsuccessful\n"));
|
|
}
|
|
|
|
SockThreadProcessingGetXByY = FALSE;
|
|
SetLastError( WSANO_DATA );
|
|
WS_EXIT( "GETXBYYSP_gethostbyaddr", 0, TRUE );
|
|
return ((struct hostent *) NULL);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
_sethtent (
|
|
IN int f
|
|
)
|
|
{
|
|
if (hostf == NULL) {
|
|
hostf = SockOpenNetworkDataBase("hosts", HOSTDB, HOSTDB_SIZE, "r");
|
|
|
|
} else {
|
|
rewind(hostf);
|
|
}
|
|
stayopen |= f;
|
|
|
|
} // _sethtent
|
|
|
|
|
|
void
|
|
_endhtent (
|
|
void
|
|
)
|
|
{
|
|
if (hostf && !stayopen) {
|
|
(void) fclose(hostf);
|
|
hostf = NULL;
|
|
}
|
|
|
|
} // _endhtent
|
|
|
|
|
|
struct hostent *
|
|
_gethtent (
|
|
void
|
|
)
|
|
{
|
|
char *p;
|
|
register char *cp, **q;
|
|
|
|
if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL) {
|
|
IF_DEBUG(GETXBYY) {
|
|
WS_PRINT(("\tERROR: cannot open hosts database file %s\n",
|
|
HOSTDB));
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
again:
|
|
if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL) {
|
|
return (NULL);
|
|
}
|
|
|
|
if (*p == '#') {
|
|
goto again;
|
|
}
|
|
|
|
cp = strpbrk(p, "#\n");
|
|
|
|
if (cp != NULL) {
|
|
*cp = '\0';
|
|
}
|
|
|
|
cp = strpbrk(p, " \t");
|
|
|
|
if (cp == NULL) {
|
|
goto again;
|
|
}
|
|
|
|
*cp++ = '\0';
|
|
/* THIS STUFF IS INTERNET SPECIFIC */
|
|
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
|
|
host.h_addr_list = host_addrs;
|
|
#endif
|
|
host.h_addr = hostaddr;
|
|
|
|
*((long *)host.h_addr) = inet_addr(p);
|
|
|
|
//
|
|
// If the address in the hosts file is bogus, skip over the
|
|
// entry.
|
|
//
|
|
|
|
if ( *((long *)host.h_addr) == INADDR_NONE &&
|
|
_strnicmp( "255.255.255.255", p, 15 ) != 0 ) {
|
|
goto again;
|
|
}
|
|
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
while (*cp == ' ' || *cp == '\t')
|
|
cp++;
|
|
host.h_name = cp;
|
|
q = host.h_aliases = host_aliases;
|
|
cp = strpbrk(cp, " \t");
|
|
|
|
if (cp != NULL) {
|
|
*cp++ = '\0';
|
|
}
|
|
|
|
while (cp && *cp) {
|
|
if (*cp == ' ' || *cp == '\t') {
|
|
cp++;
|
|
continue;
|
|
}
|
|
if (q < &host_aliases[MAXALIASES - 1]) {
|
|
*q++ = cp;
|
|
}
|
|
cp = strpbrk(cp, " \t");
|
|
if (cp != NULL) {
|
|
*cp++ = '\0';
|
|
}
|
|
}
|
|
*q = NULL;
|
|
|
|
return (&host);
|
|
|
|
} // _gethtent
|
|
|
|
|
|
struct hostent *
|
|
_gethtbyname (
|
|
IN char *name
|
|
)
|
|
{
|
|
register struct hostent *p;
|
|
register char **cp;
|
|
|
|
_sethtent(0);
|
|
while (p = _gethtent()) {
|
|
//if (strcasecmp(p->h_name, name) == 0) {
|
|
if (_stricmp(p->h_name, name) == 0) {
|
|
break;
|
|
}
|
|
for (cp = p->h_aliases; *cp != 0; cp++)
|
|
//if (strcasecmp(*cp, name) == 0) {
|
|
if (_stricmp(*cp, name) == 0) {
|
|
goto found;
|
|
}
|
|
}
|
|
found:
|
|
_endhtent();
|
|
return (p);
|
|
|
|
} // _gethtbyname
|
|
|
|
|
|
struct hostent *
|
|
myhostent (
|
|
void
|
|
)
|
|
{
|
|
char *bp;
|
|
ULONG ipAddrs[MAXADDRS];
|
|
int numberOfIpAddresses;
|
|
int i;
|
|
PUCHAR domain;
|
|
NTSTATUS status;
|
|
HKEY myKey;
|
|
ULONG myType;
|
|
INT nameLength;
|
|
INT bytesLeft;
|
|
|
|
extern int GetIpAddressList(LPDWORD, WORD);
|
|
|
|
host.h_addr_list = h_addr_ptrs;
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
|
|
bp = hostbuf;
|
|
|
|
if (numberOfIpAddresses = GetIpAddressList((LPDWORD)ipAddrs, MAXADDRS)) {
|
|
for (i = 0; i < numberOfIpAddresses; ++i ) {
|
|
host.h_addr_list[i] = bp;
|
|
*((LPDWORD)bp)++ = ipAddrs[i];
|
|
}
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
host.h_addr_list[i] = NULL;
|
|
|
|
//
|
|
// Create the fully qualified domain name by concatenating the domain
|
|
// name onto the host name.
|
|
//
|
|
|
|
bytesLeft = BUFSIZ - (bp - hostbuf);
|
|
_pgethostname(bp, bytesLeft);
|
|
|
|
status = SockOpenKeyEx( &myKey, VTCPPARM, NTCPPARM, TCPPARM );
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
nameLength = strlen(bp);
|
|
bytesLeft -= nameLength + 1;
|
|
domain = bp + nameLength + 1;
|
|
|
|
status = SockGetSingleValue(myKey, "Domain", domain,
|
|
&myType, bytesLeft);
|
|
if (!NT_SUCCESS(status) || (strlen(domain) == 0)) {
|
|
status = SockGetSingleValue(myKey, "DhcpDomain", domain,
|
|
&myType, bytesLeft);
|
|
}
|
|
|
|
if ( NT_SUCCESS(status) && strlen(domain) > 0 ) {
|
|
*(domain - 1) = '.';
|
|
}
|
|
|
|
NtClose(myKey);
|
|
}
|
|
|
|
host.h_name = bp;
|
|
*host_aliases = NULL;
|
|
host.h_aliases = host_aliases;
|
|
return (&host);
|
|
|
|
} // myhostent
|
|
|
|
|
|
struct hostent *
|
|
localhostent (
|
|
void
|
|
)
|
|
{
|
|
PUCHAR domain;
|
|
NTSTATUS status;
|
|
HKEY myKey;
|
|
ULONG myType;
|
|
INT nameLength;
|
|
|
|
/* THIS STUFF IS INTERNET SPECIFIC */
|
|
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
|
|
host.h_addr_list = host_addrs;
|
|
#endif
|
|
host.h_addr = hostaddr;
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
*((long *)host.h_addr) = htonl(INADDR_LOOPBACK);
|
|
|
|
//
|
|
// Create the fully qualified domain name by concatenating the domain
|
|
// name onto the host name.
|
|
//
|
|
|
|
_pgethostname(hostbuf, BUFSIZ);
|
|
|
|
status = SockOpenKeyEx( &myKey, VTCPPARM, NTCPPARM, TCPPARM );
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
nameLength = strlen(hostbuf);
|
|
domain = hostbuf + strlen(hostbuf) + 1;
|
|
|
|
status = SockGetSingleValue(myKey, "Domain", domain,
|
|
&myType, BUFSIZ - nameLength - 1);
|
|
if (!NT_SUCCESS(status) || (strlen(domain) == 0)) {
|
|
status = SockGetSingleValue(myKey, "DhcpDomain", domain,
|
|
&myType, BUFSIZ - nameLength - 1);
|
|
}
|
|
|
|
if ( NT_SUCCESS(status) && strlen(domain) > 0 ) {
|
|
*(domain - 1) = '.';
|
|
}
|
|
|
|
NtClose(myKey);
|
|
}
|
|
|
|
host.h_name = &hostbuf[0];
|
|
*host_aliases = NULL;
|
|
host.h_aliases = host_aliases;
|
|
return (&host);
|
|
|
|
} // localhostent
|
|
|
|
|
|
struct hostent *
|
|
dnshostent (
|
|
void
|
|
)
|
|
{
|
|
BOOL success;
|
|
|
|
/* THIS STUFF IS INTERNET SPECIFIC */
|
|
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
|
|
host.h_addr_list = h_addr_ptrs;
|
|
#endif
|
|
host.h_length = sizeof (unsigned long);
|
|
host.h_addrtype = AF_INET;
|
|
|
|
success = querydnsaddrs( (LPDWORD *)host.h_addr_list, hostbuf );
|
|
if ( !success ) {
|
|
return NULL;
|
|
}
|
|
|
|
host.h_name = NULL;
|
|
*host_aliases = NULL;
|
|
host.h_aliases = host_aliases;
|
|
return (&host);
|
|
|
|
} // dnshostent
|
|
|
|
|
|
struct hostent *
|
|
_gethtbyaddr (
|
|
IN char *addr,
|
|
IN int len,
|
|
IN int type
|
|
)
|
|
{
|
|
register struct hostent *p;
|
|
|
|
_sethtent(0);
|
|
|
|
while (p = _gethtent()) {
|
|
if (p->h_addrtype == type && p->h_length == len &&
|
|
!bcmp(p->h_addr, addr, len)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
_endhtent();
|
|
return (p);
|
|
|
|
} // _gethtbyaddr
|
|
|
|
|
|
DWORD
|
|
CopyHostentToBuffer (
|
|
char FAR *Buffer,
|
|
int BufferLength,
|
|
PHOSTENT Hostent
|
|
)
|
|
{
|
|
DWORD requiredBufferLength;
|
|
DWORD bytesFilled;
|
|
PCHAR currentLocation = Buffer;
|
|
DWORD aliasCount;
|
|
DWORD addressCount;
|
|
DWORD i;
|
|
PHOSTENT outputHostent = (PHOSTENT)Buffer;
|
|
|
|
//
|
|
// Determine how many bytes are needed to fully copy the structure.
|
|
//
|
|
|
|
requiredBufferLength = BytesInHostent( Hostent );
|
|
|
|
//
|
|
// Zero the user buffer.
|
|
//
|
|
|
|
if ( (DWORD)BufferLength > requiredBufferLength ) {
|
|
RtlZeroMemory( Buffer, requiredBufferLength );
|
|
} else {
|
|
RtlZeroMemory( Buffer, BufferLength );
|
|
}
|
|
|
|
//
|
|
// Copy over the hostent structure if it fits.
|
|
//
|
|
|
|
bytesFilled = sizeof(*Hostent);
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
RtlCopyMemory( currentLocation, Hostent, sizeof(*Hostent) );
|
|
currentLocation = Buffer + bytesFilled;
|
|
|
|
outputHostent->h_name = NULL;
|
|
outputHostent->h_aliases = NULL;
|
|
outputHostent->h_addr_list = NULL;
|
|
|
|
//
|
|
// Count the host's aliases and set up an array to hold pointers to
|
|
// them.
|
|
//
|
|
|
|
for ( aliasCount = 0;
|
|
Hostent->h_aliases[aliasCount] != NULL;
|
|
aliasCount++ );
|
|
|
|
bytesFilled += (aliasCount+1) * sizeof(char FAR *);
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
Hostent->h_aliases = NULL;
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
outputHostent->h_aliases = (char FAR * FAR *)currentLocation;
|
|
currentLocation = Buffer + bytesFilled;
|
|
|
|
//
|
|
// Count the host's addresses and set up an array to hold pointers to
|
|
// them.
|
|
//
|
|
|
|
for ( addressCount = 0;
|
|
Hostent->h_addr_list[addressCount] != NULL;
|
|
addressCount++ );
|
|
|
|
bytesFilled += (addressCount+1) * sizeof(void FAR *);
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
Hostent->h_addr_list = NULL;
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
outputHostent->h_addr_list = (char FAR * FAR *)currentLocation;
|
|
currentLocation = Buffer + bytesFilled;
|
|
|
|
//
|
|
// Start filling in addresses. Do addresses before filling in the
|
|
// host name and aliases in order to avoid alignment problems.
|
|
//
|
|
|
|
for ( i = 0; i < addressCount; i++ ) {
|
|
|
|
bytesFilled += Hostent->h_length;
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
outputHostent->h_addr_list[i] = NULL;
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
outputHostent->h_addr_list[i] = currentLocation;
|
|
|
|
RtlCopyMemory(
|
|
currentLocation,
|
|
Hostent->h_addr_list[i],
|
|
Hostent->h_length
|
|
);
|
|
|
|
currentLocation = Buffer + bytesFilled;
|
|
}
|
|
|
|
outputHostent->h_addr_list[i] = NULL;
|
|
|
|
//
|
|
// Copy the host name if it fits.
|
|
//
|
|
|
|
bytesFilled += strlen( Hostent->h_name ) + 1;
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
outputHostent->h_name = currentLocation;
|
|
|
|
RtlCopyMemory( currentLocation, Hostent->h_name, strlen( Hostent->h_name ) + 1 );
|
|
currentLocation = Buffer + bytesFilled;
|
|
|
|
//
|
|
// Start filling in aliases.
|
|
//
|
|
|
|
for ( i = 0; i < aliasCount; i++ ) {
|
|
|
|
bytesFilled += strlen( Hostent->h_aliases[i] ) + 1;
|
|
|
|
if ( bytesFilled > (DWORD)BufferLength ) {
|
|
outputHostent->h_aliases[i] = NULL;
|
|
return requiredBufferLength;
|
|
}
|
|
|
|
outputHostent->h_aliases[i] = currentLocation;
|
|
|
|
RtlCopyMemory(
|
|
currentLocation,
|
|
Hostent->h_aliases[i],
|
|
strlen( Hostent->h_aliases[i] ) + 1
|
|
);
|
|
|
|
currentLocation = Buffer + bytesFilled;
|
|
}
|
|
|
|
outputHostent->h_aliases[i] = NULL;
|
|
|
|
return requiredBufferLength;
|
|
|
|
} // CopyHostentToBuffer
|
|
|
|
|
|
DWORD
|
|
BytesInHostent (
|
|
PHOSTENT Hostent
|
|
)
|
|
{
|
|
DWORD total;
|
|
int i;
|
|
|
|
total = sizeof(HOSTENT);
|
|
total += strlen( Hostent->h_name ) + 1;
|
|
|
|
//
|
|
// Account for the NULL terminator pointers at the end of the
|
|
// alias and address arrays.
|
|
//
|
|
|
|
total += sizeof(char *) + sizeof(char *);
|
|
|
|
for ( i = 0; Hostent->h_aliases[i] != NULL; i++ ) {
|
|
total += strlen( Hostent->h_aliases[i] ) + 1 + sizeof(char *);
|
|
}
|
|
|
|
for ( i = 0; Hostent->h_addr_list[i] != NULL; i++ ) {
|
|
total += Hostent->h_length + sizeof(char *);
|
|
}
|
|
|
|
//
|
|
// Pad the answer to an eight-byte boundary.
|
|
//
|
|
|
|
return (total + 7) & ~7;
|
|
|
|
} // BytesInHostent
|
|
|
|
typedef struct _SOCK_NBT_NAMERES_INFO {
|
|
IO_STATUS_BLOCK IoStatus;
|
|
struct {
|
|
FIND_NAME_HEADER Header;
|
|
FIND_NAME_BUFFER Buffer;
|
|
} FindNameInfo;
|
|
tIPADDR_BUFFER IpAddrInfo;
|
|
} SOCK_NBT_NAMERES_INFO, *PSOCK_NBT_NAMERES_INFO;
|
|
|
|
|
|
ULONG
|
|
SockNbtResolveName (
|
|
IN PCHAR Name
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG ipAddr = INADDR_NONE;
|
|
ULONG i;
|
|
ULONG j;
|
|
DWORD completed;
|
|
DWORD handleCount;
|
|
DWORD waitCount;
|
|
ULONG nameLength;
|
|
PHANDLE events = NULL;
|
|
PSOCK_NBT_NAMERES_INFO nameresInfo = NULL;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
//
|
|
// If the passed-in name is longer than 15 characters, then we know
|
|
// that it can't be resolved with Netbios.
|
|
//
|
|
|
|
nameLength = strlen( Name );
|
|
|
|
if ( nameLength > 15 ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open control channels to NBT.
|
|
//
|
|
|
|
handleCount = SockOpenNbt();
|
|
|
|
if( handleCount == 0 ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open event objects for synchronization of I/O completion.
|
|
//
|
|
|
|
events = ALLOCATE_HEAP( handleCount * sizeof(HANDLE) );
|
|
if ( events == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory( events, handleCount * sizeof(HANDLE) );
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
events[j] = CreateEvent( NULL, TRUE, TRUE, NULL );
|
|
if ( events[j] == NULL ) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate an array of structures, one for each nameres request.
|
|
//
|
|
|
|
nameresInfo = ALLOCATE_HEAP( handleCount * sizeof(*nameresInfo) );
|
|
if ( nameresInfo == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set up several name resolution requests.
|
|
//
|
|
|
|
waitCount = 0;
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
|
|
//
|
|
// Set up the input buffer with the name of the host we're looking
|
|
// for. We upcase the name, zero pad to 15 spaces, and put a 0 in
|
|
// the last byte to search for the redirector name.
|
|
//
|
|
|
|
for ( i = 0; i < nameLength; i++ ) {
|
|
if ( islower( Name[i] ) ) {
|
|
nameresInfo[j].IpAddrInfo.Name[i] = toupper( Name[i] );
|
|
} else {
|
|
nameresInfo[j].IpAddrInfo.Name[i] = Name[i];
|
|
}
|
|
}
|
|
|
|
while ( i < 15 ) {
|
|
nameresInfo[j].IpAddrInfo.Name[i++] = ' ';
|
|
}
|
|
|
|
nameresInfo[j].IpAddrInfo.Name[15] = 0;
|
|
|
|
//
|
|
// Do the actual query find name.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
SockNbtHandles[j],
|
|
events[j],
|
|
NULL,
|
|
NULL,
|
|
&nameresInfo[j].IoStatus,
|
|
IOCTL_NETBT_FIND_NAME,
|
|
&nameresInfo[j].IpAddrInfo,
|
|
sizeof(nameresInfo[j].IpAddrInfo),
|
|
&nameresInfo[j].FindNameInfo,
|
|
sizeof(nameresInfo[j].FindNameInfo)
|
|
);
|
|
if( NT_SUCCESS(status) ) {
|
|
HANDLE tmp;
|
|
|
|
tmp = events[j];
|
|
events[j] = NULL;
|
|
events[waitCount++] = tmp;
|
|
|
|
if( status != STATUS_PENDING ) {
|
|
nameresInfo[j].IoStatus.Status = status;
|
|
}
|
|
} else {
|
|
nameresInfo[j].IoStatus.Status = status;
|
|
NtClose( events[j] );
|
|
events[j] = NULL;
|
|
}
|
|
}
|
|
|
|
if( waitCount == 0 ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Wait for one of the requests to complete. We'll take the first
|
|
// successful response we get.
|
|
//
|
|
|
|
completed =
|
|
WaitForMultipleObjects( waitCount, events, FALSE, INFINITE );
|
|
|
|
//
|
|
// Cancel all the outstanding requests. This prevents the query
|
|
// from taking a long time on a multihomed machine where only
|
|
// one of the queries is going to succeed.
|
|
//
|
|
|
|
for ( j = 0; j < waitCount; j++ ) {
|
|
if ( (completed - WAIT_OBJECT_0) != j ) {
|
|
NtCancelIoFile( SockNbtHandles[j], &ioStatusBlock );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for all the rest of the IO requests to complete.
|
|
//
|
|
|
|
WaitForMultipleObjects( waitCount, events, TRUE, INFINITE );
|
|
|
|
//
|
|
// Walk through the requests and see if any succeeded.
|
|
//
|
|
|
|
for ( j = 0; j < waitCount; j++ ) {
|
|
|
|
if ( !NT_SUCCESS(nameresInfo[j].IoStatus.Status) ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// This request succeeded. The IP address is in the rightmost
|
|
// four bytes of the source_addr field.
|
|
//
|
|
|
|
ipAddr = *(UNALIGNED ULONG *)
|
|
(&(nameresInfo[j].FindNameInfo.Buffer.source_addr[2]));
|
|
|
|
if ( ipAddr == 0 ) {
|
|
ipAddr = INADDR_NONE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
|
|
exit:
|
|
|
|
if ( events != NULL ) {
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
if ( events[j] != NULL ) {
|
|
NtClose( events[j] );
|
|
}
|
|
}
|
|
FREE_HEAP( events );
|
|
}
|
|
|
|
if ( nameresInfo != NULL ) {
|
|
FREE_HEAP( nameresInfo );
|
|
}
|
|
|
|
return ipAddr;
|
|
|
|
} // SockNbtResolveName
|
|
|
|
typedef struct _SOCK_NBT_ADDRRES_INFO {
|
|
IO_STATUS_BLOCK IoStatus;
|
|
tIPANDNAMEINFO IpAndNameInfo;
|
|
CHAR Buffer[2048];
|
|
} SOCK_NBT_ADDRRES_INFO, *PSOCK_NBT_ADDRRES_INFO;
|
|
|
|
|
|
BOOL
|
|
SockNbtResolveAddr (
|
|
IN ULONG IpAddress,
|
|
IN PCHAR Name
|
|
)
|
|
{
|
|
LONG Count;
|
|
INT i;
|
|
UINT j;
|
|
NTSTATUS status;
|
|
tADAPTERSTATUS *pAdapterStatus;
|
|
NAME_BUFFER *pNames;
|
|
ULONG SizeInput;
|
|
PSOCK_NBT_ADDRRES_INFO addrresInfo = NULL;
|
|
PHANDLE events = NULL;
|
|
BOOL success = FALSE;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
DWORD completed;
|
|
DWORD handleCount;
|
|
DWORD waitCount;
|
|
|
|
//
|
|
// Open control channels to NBT.
|
|
//
|
|
|
|
handleCount = SockOpenNbt();
|
|
|
|
if( handleCount == 0 ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Don't allow zero for the address since it sends a broadcast and
|
|
// every one responds
|
|
//
|
|
|
|
if ((IpAddress == INADDR_NONE) || (IpAddress == 0)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open event objects for synchronization of I/O completion.
|
|
//
|
|
|
|
events = ALLOCATE_HEAP( handleCount * sizeof(HANDLE) );
|
|
if ( events == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory( events, handleCount * sizeof(HANDLE) );
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
events[j] = CreateEvent( NULL, TRUE, TRUE, NULL );
|
|
if ( events[j] == NULL ) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate an array of structures, one for each addrres request.
|
|
//
|
|
|
|
addrresInfo = ALLOCATE_HEAP( handleCount * sizeof(*addrresInfo) );
|
|
if ( addrresInfo == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set up several name resolution requests.
|
|
//
|
|
|
|
waitCount = 0;
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
|
|
RtlZeroMemory( &addrresInfo[j].IpAndNameInfo, sizeof(tIPANDNAMEINFO) );
|
|
|
|
addrresInfo[j].IpAndNameInfo.IpAddress = ntohl(IpAddress);
|
|
addrresInfo[j].IpAndNameInfo.NetbiosAddress.Address[0].Address[0].NetbiosName[0] = '*';
|
|
|
|
addrresInfo[j].IpAndNameInfo.NetbiosAddress.TAAddressCount = 1;
|
|
addrresInfo[j].IpAndNameInfo.NetbiosAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
addrresInfo[j].IpAndNameInfo.NetbiosAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
addrresInfo[j].IpAndNameInfo.NetbiosAddress.Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
|
|
SizeInput = sizeof(tIPANDNAMEINFO);
|
|
|
|
//
|
|
// Do the actual query find name.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
SockNbtHandles[j],
|
|
events[j],
|
|
NULL,
|
|
NULL,
|
|
&addrresInfo[j].IoStatus,
|
|
IOCTL_NETBT_ADAPTER_STATUS,
|
|
&addrresInfo[j].IpAndNameInfo,
|
|
sizeof(addrresInfo[j].IpAndNameInfo),
|
|
addrresInfo[j].Buffer,
|
|
sizeof(addrresInfo[j].Buffer)
|
|
);
|
|
if( NT_SUCCESS(status) ) {
|
|
HANDLE tmp;
|
|
|
|
tmp = events[j];
|
|
events[j] = NULL;
|
|
events[waitCount++] = tmp;
|
|
|
|
if( status != STATUS_PENDING ) {
|
|
addrresInfo[j].IoStatus.Status = status;
|
|
}
|
|
} else {
|
|
addrresInfo[j].IoStatus.Status = status;
|
|
NtClose( events[j] );
|
|
events[j] = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for one of the requests to complete. We'll take the first
|
|
// successful response we get.
|
|
//
|
|
|
|
completed =
|
|
WaitForMultipleObjects( waitCount, events, FALSE, INFINITE );
|
|
|
|
//
|
|
// Cancel all the outstanding requests. This prevents the query
|
|
// from taking a long time on a multihomed machine where only
|
|
// one of the queries is going to succeed.
|
|
//
|
|
|
|
for ( j = 0; j < waitCount; j++ ) {
|
|
if ( (completed - WAIT_OBJECT_0) != j ) {
|
|
NtCancelIoFile( SockNbtHandles[j], &ioStatusBlock );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for all the rest of the IO requests to complete.
|
|
//
|
|
|
|
WaitForMultipleObjects( waitCount, events, TRUE, INFINITE );
|
|
|
|
//
|
|
// Walk through the requests and see if any succeeded.
|
|
//
|
|
|
|
for ( j = 0; j < waitCount; j++ ) {
|
|
|
|
pAdapterStatus = (tADAPTERSTATUS *)addrresInfo[j].Buffer;
|
|
|
|
if ( !NT_SUCCESS(addrresInfo[j].IoStatus.Status) ||
|
|
pAdapterStatus->AdapterInfo.name_count == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
pNames = pAdapterStatus->Names;
|
|
Count = pAdapterStatus->AdapterInfo.name_count;
|
|
|
|
//
|
|
// Look for the redirector name in the list.
|
|
//
|
|
|
|
while(Count--) {
|
|
|
|
if ( pNames->name[NCBNAMSZ-1] == 0 ) {
|
|
|
|
//
|
|
// Copy the name up to but not including the first space.
|
|
//
|
|
|
|
for ( i = 0; i < NCBNAMSZ && pNames->name[i] != ' '; i++ ) {
|
|
*(Name + i) = pNames->name[i];
|
|
}
|
|
|
|
*(Name + i) = '\0';
|
|
|
|
success = TRUE;
|
|
goto exit;
|
|
}
|
|
|
|
pNames++;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( events != NULL ) {
|
|
|
|
for ( j = 0; j < handleCount; j++ ) {
|
|
if ( events[j] != NULL ) {
|
|
NtClose( events[j] );
|
|
}
|
|
}
|
|
FREE_HEAP( events );
|
|
}
|
|
|
|
if ( addrresInfo != NULL ) {
|
|
FREE_HEAP( addrresInfo );
|
|
}
|
|
|
|
return success;
|
|
|
|
} // SockNbtResolveAddr
|
|
|
|
|
|
DWORD
|
|
SockOpenNbt (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens control channel(s) to the NBT device(s).
|
|
|
|
N.B. The Plug & Play enabled NBT creates its device objects on demand
|
|
when the underlying media becomes available. As a result of this,
|
|
devices in NBT's device list may not be immediately available, and
|
|
trying to open these devices will result in error. This routine caches
|
|
NBT control channels as they are opened. Subsequent calls attempt to
|
|
open any control channels that are not already open.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
DWORD - The number of control channels opened.
|
|
|
|
Notes:
|
|
|
|
This routine caches open NBT handles for performance. The following
|
|
global variables are used for this cache:
|
|
|
|
SockNbtDeviceNames - Pointer to a REG_MULTI_SZ buffer containing
|
|
all of the potential NBT names.
|
|
|
|
SockNbtDeviceCount - The number of device names in the above buffer.
|
|
|
|
SockNbtHandles - Pointer to an array of open HANDLEs. Note that this
|
|
array is "packed" (all entries are non-NULL) and is thus
|
|
suitable for passing to WaitForMultipleObjects().
|
|
|
|
SockNbtHandleCount - The number of open HANDLEs in the above array.
|
|
This value is always <= SockNbtDeviceCount.
|
|
|
|
SockSparseNbtHandles - Pointer to a sparse array of HANDLEs. Each
|
|
entry in this array is either NULL (meaning that the control
|
|
channel has not yet been opened) or !NULL (meaning that the
|
|
control channel has been opened). Since this array may contain
|
|
NULL entries, it is *not* suitable for WaitForMultipleObjects().
|
|
|
|
SockNbtFullyInitialized - Set to TRUE after all NBT devices have
|
|
been successfully opened. This lets us short-circuit a bunch
|
|
of tests after all control channels are open.
|
|
|
|
Note that SockNbtHandles and SockSparseNbtHandles are allocated from
|
|
the same heap block (saves an extra allocation).
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY nbtKey = NULL;
|
|
ULONG error;
|
|
ULONG deviceNameLength;
|
|
ULONG type;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
UNICODE_STRING deviceString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
PWSTR w;
|
|
DWORD i;
|
|
DWORD handleCount;
|
|
|
|
//
|
|
// First determine whether we actually need to open NBT.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
|
|
if( SockNbtFullyInitialized ) {
|
|
SockReleaseGlobalLock( );
|
|
return SockNbtHandleCount;
|
|
}
|
|
|
|
//
|
|
// Next, read the registry to obtain the device name of one of
|
|
// NBT's device exports.
|
|
//
|
|
// N.B. This assumes the list of NBT device names is fairly static
|
|
// (i.e. we only read it from the registry once per process).
|
|
//
|
|
|
|
if( SockNbtDeviceNames == NULL ) {
|
|
|
|
error = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\NetBT\\Linkage",
|
|
0,
|
|
KEY_READ,
|
|
&nbtKey
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Determine the size of the device name. We need this so that we
|
|
// can allocate enough memory to hold it.
|
|
//
|
|
|
|
deviceNameLength = 0;
|
|
|
|
error = RegQueryValueExW(
|
|
nbtKey,
|
|
L"Export",
|
|
NULL,
|
|
&type,
|
|
NULL,
|
|
&deviceNameLength
|
|
);
|
|
if ( error != ERROR_MORE_DATA && error != NO_ERROR ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Allocate enough memory to hold the mapping.
|
|
//
|
|
|
|
SockNbtDeviceNames = ALLOCATE_HEAP( deviceNameLength );
|
|
if ( SockNbtDeviceNames == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get the actual device names from the registry.
|
|
//
|
|
|
|
error = RegQueryValueExW(
|
|
nbtKey,
|
|
L"Export",
|
|
NULL,
|
|
&type,
|
|
(PVOID)SockNbtDeviceNames,
|
|
&deviceNameLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
FREE_HEAP( SockNbtDeviceNames );
|
|
SockNbtDeviceNames = NULL;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Count the number of names exported by NetBT.
|
|
//
|
|
|
|
SockNbtDeviceCount = 0;
|
|
|
|
for ( w = SockNbtDeviceNames; *w != L'\0'; w += wcslen(w) + 1 ) {
|
|
SockNbtDeviceCount++;
|
|
}
|
|
|
|
if ( SockNbtDeviceCount == 0 ) {
|
|
SockNbtFullyInitialized = TRUE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
WS_ASSERT( SockNbtDeviceNames != NULL );
|
|
WS_ASSERT( SockNbtDeviceCount > 0 );
|
|
|
|
//
|
|
// Allocate space to hold all the handles.
|
|
//
|
|
|
|
if( SockNbtHandles == NULL ) {
|
|
|
|
WS_ASSERT( SockSparseNbtHandles == NULL );
|
|
|
|
SockNbtHandles = ALLOCATE_HEAP(
|
|
(SockNbtDeviceCount+1) * sizeof(HANDLE) * 2
|
|
);
|
|
|
|
if( SockNbtHandles == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
SockNbtHandles,
|
|
(SockNbtDeviceCount+1) * sizeof(HANDLE) * 2
|
|
);
|
|
|
|
SockSparseNbtHandles = SockNbtHandles + (SockNbtDeviceCount+1);
|
|
|
|
}
|
|
|
|
//
|
|
// For each exported name, open a control channel handle to NBT.
|
|
//
|
|
|
|
SockNbtHandleCount = 0;
|
|
|
|
for ( i = 0, w = SockNbtDeviceNames; *w != L'\0'; i++, w += wcslen(w) + 1 ) {
|
|
|
|
WS_ASSERT( i < SockNbtDeviceCount );
|
|
|
|
if( SockSparseNbtHandles[i] != NULL ) {
|
|
SockNbtHandles[SockNbtHandleCount] = SockSparseNbtHandles[i];
|
|
SockNbtHandleCount++;
|
|
continue;
|
|
}
|
|
|
|
RtlInitUnicodeString( &deviceString, w );
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&deviceString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
&SockSparseNbtHandles[i],
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
NULL, // AllocationSize
|
|
0L, // FileAttributes
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // ShareAccess
|
|
FILE_OPEN_IF, // CreateDisposition
|
|
0, // CreateOptions
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
SockNbtHandles[SockNbtHandleCount] = SockSparseNbtHandles[i];
|
|
SockNbtHandleCount++;
|
|
}
|
|
}
|
|
|
|
if( SockNbtHandleCount == SockNbtDeviceCount ) {
|
|
SockNbtFullyInitialized = TRUE;
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( nbtKey != NULL ) {
|
|
RegCloseKey( nbtKey );
|
|
}
|
|
|
|
handleCount = SockNbtHandleCount;
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
return handleCount;
|
|
|
|
} // SockOpenNbt
|
|
|
|
|
|
VOID
|
|
GetHostCleanup(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
if( SockNbtDeviceNames != NULL ) {
|
|
FREE_HEAP( SockNbtDeviceNames );
|
|
SockNbtDeviceNames = NULL;
|
|
}
|
|
|
|
if( SockNbtHandles != NULL ) {
|
|
for( i = 0 ; i < SockNbtHandleCount ; i++ ) {
|
|
if( SockNbtHandles[i] != NULL ) {
|
|
CloseHandle( SockNbtHandles[i] );
|
|
SockNbtHandles[i] = NULL;
|
|
}
|
|
}
|
|
|
|
FREE_HEAP( SockNbtHandles );
|
|
SockNbtHandles = NULL;
|
|
}
|
|
|
|
} // GetHostCleanup
|
|
|