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.
682 lines
15 KiB
682 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Inet.c
|
|
|
|
Abstract:
|
|
|
|
Fake net.exe for use on the Internet. The implementation is a
|
|
complete and utter hack, but it works and may be useful for the
|
|
reskit.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 8-Apr-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define FD_SETSIZE 1000
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winsock.h>
|
|
#include <nbtioctl.h>
|
|
#include <nb30.h>
|
|
#include <nspapi.h>
|
|
#include <svcguid.h>
|
|
|
|
DWORD NbtHandleCount;
|
|
PHANDLE NbtHandles;
|
|
BOOL Verbose = FALSE;
|
|
GUID HostnameGuid = SVCID_HOSTNAME;
|
|
|
|
typedef struct _NBT_ADDRRES_INFO {
|
|
IO_STATUS_BLOCK IoStatus;
|
|
tIPANDNAMEINFO IpAndNameInfo;
|
|
CHAR Buffer[2048];
|
|
} NBT_ADDRRES_INFO, *PNBT_ADDRRES_INFO;
|
|
|
|
typedef struct
|
|
{
|
|
ADAPTER_STATUS AdapterInfo;
|
|
NAME_BUFFER Names[32];
|
|
} tADAPTERSTATUS;
|
|
|
|
BOOL
|
|
NbtResolveAddr (
|
|
IN ULONG IpAddress,
|
|
IN PCHAR Name
|
|
);
|
|
|
|
BOOL
|
|
OpenNbt (
|
|
VOID
|
|
);
|
|
|
|
|
|
BOOL
|
|
ConvertTcpipNameToNetbios (
|
|
IN LPSTR UncName,
|
|
OUT LPSTR *NewUncName,
|
|
OUT LPDWORD IpAddress,
|
|
OUT LPSTR NetbiosName
|
|
);
|
|
|
|
void _CRTAPI1
|
|
main (
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
WSADATA wsaData;
|
|
LPSTR newName;
|
|
IN_ADDR ipAddress;
|
|
CHAR netbiosName[16];
|
|
INT i;
|
|
BOOL success;
|
|
CHAR newCommandLine[1024];
|
|
DWORD count;
|
|
BYTE buffer[4096];
|
|
DWORD bufferSize = 4096;
|
|
|
|
(VOID)WSAStartup( 0x0101, &wsaData );
|
|
|
|
if ( argc <= 1 ) {
|
|
printf( "Usage: inet [/v] [net command]\n" );
|
|
exit(1);
|
|
}
|
|
|
|
//
|
|
// If the first argument is "/v", go into verbose mode and shift the
|
|
// other arguments forward.
|
|
//
|
|
|
|
if ( _stricmp( argv[1], "/v" ) == 0 ) {
|
|
Verbose = TRUE;
|
|
for ( i = 2; i < argc; i++ ) {
|
|
argv[i-1] = argv[i];
|
|
}
|
|
argc -= 1;
|
|
printf( "\n" );
|
|
}
|
|
|
|
//
|
|
// Walk through the command-line arguments and convert any UNC names
|
|
// we find to netbios so that NetBT can understand them.
|
|
//
|
|
|
|
for ( i = 1; i < argc; i++ ) {
|
|
|
|
//
|
|
// Only parse arguments starting with "\\". Ignore all other
|
|
// arguments.
|
|
//
|
|
|
|
if ( *argv[i] == '\0' ||
|
|
*argv[i] != '\\' ||
|
|
*(argv[i]+1) != '\\' ) {
|
|
continue;
|
|
}
|
|
|
|
success = ConvertTcpipNameToNetbios(
|
|
argv[i],
|
|
&newName,
|
|
&ipAddress.s_addr,
|
|
netbiosName
|
|
);
|
|
|
|
if ( Verbose ) {
|
|
printf( "Converted %s into %s\n", argv[i], newName );
|
|
printf( " NetBIOS name %s has IP address %s\n",
|
|
netbiosName, inet_ntoa( ipAddress ) );
|
|
}
|
|
|
|
//
|
|
// Determine whether we can resolve this new Netbios name into
|
|
// an IP address via NetBT. If we cannot, then we'll have to
|
|
// add it to LMHOSTS so that NetBT can find it.
|
|
//
|
|
|
|
count = GetAddressByNameA(
|
|
NS_NETBT,
|
|
&HostnameGuid,
|
|
(char *)netbiosName,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
buffer,
|
|
&bufferSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( count <= 0 ) {
|
|
|
|
//
|
|
// NetBT is unable to forward-resolve the NetBIOS name into
|
|
// an IP address. Add the mapping to LMHOSTS and reload
|
|
// the LMHOSTS file.
|
|
//
|
|
|
|
if ( Verbose ) {
|
|
printf( "Adding %s == %s to LMHOSTS file.\n",
|
|
netbiosName, inet_ntoa( ipAddress ) );
|
|
|
|
}
|
|
|
|
sprintf( newCommandLine,
|
|
"echo %s\t%s\t\t#PRE\t#Auto-added by inet.exe >> ",
|
|
inet_ntoa( ipAddress ), netbiosName );
|
|
strcat( newCommandLine, "%WINDIR%\\system32\\drivers\\etc\\lmhosts" );
|
|
system( newCommandLine );
|
|
|
|
if ( Verbose ) {
|
|
printf( "Reloading the NetBT name cache.\n" );
|
|
}
|
|
|
|
system( "nbtstat -R" );
|
|
}
|
|
|
|
argv[i] = newName;
|
|
}
|
|
|
|
strcpy( newCommandLine, "net " );
|
|
|
|
for ( i = 1; i < argc; i++ ) {
|
|
strcat( newCommandLine, argv[i] );
|
|
strcat( newCommandLine, " " );
|
|
}
|
|
|
|
if ( Verbose ) {
|
|
printf( "Executing new command line \"%s\"\n", newCommandLine );
|
|
}
|
|
|
|
system( newCommandLine );
|
|
|
|
} // main
|
|
|
|
|
|
BOOL
|
|
ConvertTcpipNameToNetbios (
|
|
IN LPSTR UncName,
|
|
OUT LPSTR *NewUncName,
|
|
OUT LPDWORD IpAddress,
|
|
OUT LPSTR NetbiosName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD ServerNameLength;
|
|
LPSTR w;
|
|
unsigned long IpAddr;
|
|
BOOL success;
|
|
NTSTATUS status;
|
|
PHOSTENT Hostent;
|
|
CHAR serverName[256];
|
|
LPSTR newUncName;
|
|
|
|
//
|
|
// First extract the server name from the UNC name, being careful
|
|
// to skip over a "@" character if specified after the leading
|
|
// "\\".
|
|
//
|
|
|
|
for (ServerNameLength = 0, w = UncName + 2;
|
|
*w != '\0' && *w != '\\';
|
|
ServerNameLength++, w++) {
|
|
|
|
serverName[ServerNameLength] = *w;
|
|
}
|
|
|
|
serverName[ServerNameLength] = '\0';
|
|
|
|
//
|
|
// Determine if this name can be resolved using TCP/IP.
|
|
//
|
|
|
|
IpAddr = inet_addr(serverName);
|
|
|
|
if (IpAddr == INADDR_NONE) {
|
|
|
|
Hostent = gethostbyname(serverName);
|
|
|
|
if (Hostent == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
IpAddr = *(PDWORD)Hostent->h_addr;
|
|
}
|
|
|
|
*IpAddress = IpAddr;
|
|
|
|
//
|
|
// It is a TCP/IP name. Allocate space to hold the new UNC name.
|
|
//
|
|
|
|
newUncName = LocalAlloc( LMEM_FIXED, strlen(UncName)+40 );
|
|
if (newUncName == NULL) {
|
|
return FALSE;
|
|
}
|
|
*NewUncName = newUncName;
|
|
|
|
memset( newUncName, 0, strlen(UncName)+40 );
|
|
|
|
//
|
|
// Get the server NetBIOS name from the IP address by using NetBIOS
|
|
// remote adapter status.
|
|
//
|
|
|
|
success = NbtResolveAddr(IpAddr, newUncName+2);
|
|
if (!success) {
|
|
LocalFree(NewUncName);
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy( NetbiosName, newUncName+2 );
|
|
|
|
//
|
|
// Build the new UNC name using the NetBIOS name we just obtained.
|
|
//
|
|
|
|
*newUncName = '\\';
|
|
*(newUncName+1) = '\\';
|
|
|
|
strcat( newUncName, w );
|
|
|
|
//
|
|
// Everything worked!
|
|
//
|
|
|
|
return TRUE;
|
|
|
|
} // ConvertTcpipNameToNetbios
|
|
|
|
|
|
BOOL
|
|
NbtResolveAddr (
|
|
IN ULONG IpAddress,
|
|
IN PCHAR Name
|
|
)
|
|
{
|
|
LONG Count;
|
|
INT i;
|
|
UINT j;
|
|
NTSTATUS status;
|
|
tADAPTERSTATUS *pAdapterStatus;
|
|
NAME_BUFFER *pNames;
|
|
ULONG SizeInput;
|
|
PNBT_ADDRRES_INFO addrresInfo = NULL;
|
|
PHANDLE events = NULL;
|
|
BOOL success = FALSE;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
DWORD completed;
|
|
|
|
//
|
|
// Open control channels to NBT.
|
|
//
|
|
|
|
if ( !OpenNbt( ) ) {
|
|
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 = LocalAlloc( LMEM_FIXED, (NbtHandleCount+1)*sizeof(HANDLE) );
|
|
if ( events == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory( events, (NbtHandleCount+1)*sizeof(HANDLE) );
|
|
|
|
for ( j = 0; j < NbtHandleCount; 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 = LocalAlloc( LMEM_FIXED, NbtHandleCount * sizeof(*addrresInfo) );
|
|
if ( addrresInfo == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set up several name resolution requests.
|
|
//
|
|
|
|
for ( j = 0; j < NbtHandleCount; 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(
|
|
NbtHandles[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 ( status != STATUS_PENDING ) {
|
|
addrresInfo[j].IoStatus.Status = status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for one of the requests to complete. We'll take the first
|
|
// successful response we get.
|
|
//
|
|
|
|
completed =
|
|
WaitForMultipleObjects( NbtHandleCount, 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 < NbtHandleCount; j++ ) {
|
|
if ( (completed - WAIT_OBJECT_0) != j ) {
|
|
NtCancelIoFile( NbtHandles[j], &ioStatusBlock );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wait for all the rest of the IO requests to complete.
|
|
//
|
|
|
|
WaitForMultipleObjects( NbtHandleCount, events, TRUE, INFINITE );
|
|
|
|
//
|
|
// Walk through the requests and see if any succeeded.
|
|
//
|
|
|
|
for ( j = 0; j < NbtHandleCount; 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 < NbtHandleCount; j++ ) {
|
|
if ( events[j] != NULL ) {
|
|
NtClose( events[j] );
|
|
}
|
|
}
|
|
LocalFree( events );
|
|
}
|
|
|
|
if ( addrresInfo != NULL ) {
|
|
LocalFree( addrresInfo );
|
|
}
|
|
|
|
return success;
|
|
|
|
} // NbtResolveAddr
|
|
|
|
|
|
BOOL
|
|
OpenNbt (
|
|
VOID
|
|
)
|
|
{
|
|
HKEY nbtKey = NULL;
|
|
ULONG error;
|
|
PWSTR deviceName = NULL;
|
|
ULONG deviceNameLength;
|
|
ULONG type;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
UNICODE_STRING deviceString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
PWSTR w;
|
|
DWORD i;
|
|
|
|
//
|
|
// First determine whether we actually need to open NBT.
|
|
//
|
|
|
|
if ( NbtHandleCount > 0 ) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// First read the registry to obtain the device name of one of
|
|
// NBT's device exports.
|
|
//
|
|
|
|
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.
|
|
//
|
|
|
|
deviceName = LocalAlloc( LMEM_FIXED, deviceNameLength );
|
|
if ( deviceName == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get the actual device names from the registry.
|
|
//
|
|
|
|
error = RegQueryValueExW(
|
|
nbtKey,
|
|
L"Export",
|
|
NULL,
|
|
&type,
|
|
(PVOID)deviceName,
|
|
&deviceNameLength
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Count the number of names exported by NetBT.
|
|
//
|
|
|
|
NbtHandleCount = 0;
|
|
|
|
for ( w = deviceName; *w != L'\0'; w += wcslen(w) + 1 ) {
|
|
NbtHandleCount++;
|
|
}
|
|
|
|
if ( NbtHandleCount == 0 ) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Allocate space to hold all the handles.
|
|
//
|
|
|
|
NbtHandles = LocalAlloc( LMEM_FIXED, (NbtHandleCount+1) * sizeof(HANDLE) );
|
|
if ( NbtHandles == NULL ) {
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory( NbtHandles, (NbtHandleCount+1) * sizeof(HANDLE) );
|
|
|
|
//
|
|
// For each exported name, open a control channel handle to NBT.
|
|
//
|
|
|
|
for ( i = 0, w = deviceName; *w != L'\0'; i++, w += wcslen(w) + 1 ) {
|
|
|
|
RtlInitUnicodeString( &deviceString, w );
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&deviceString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
&NbtHandles[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) ) {
|
|
NbtHandles[i] = NULL;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( nbtKey != NULL ) {
|
|
RegCloseKey( nbtKey );
|
|
}
|
|
|
|
if ( deviceName != NULL ) {
|
|
LocalFree( deviceName );
|
|
}
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
if ( NbtHandles != NULL ) {
|
|
|
|
for ( i = 0; NbtHandles[i] != NULL; i++ ) {
|
|
NtClose( NbtHandles[i] );
|
|
}
|
|
|
|
LocalFree( NbtHandles );
|
|
}
|
|
|
|
NbtHandles = NULL;
|
|
NbtHandleCount = 0;
|
|
}
|
|
|
|
return NT_SUCCESS(status);
|
|
|
|
} // OpenNbt
|
|
|
|
|