Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

583 lines
12 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
getname.c
Abstract:
This module contains support for the bind( ) WinSock API.
Author:
David Treadwell (davidtr) 21-Feb-1992
Revision History:
--*/
#include "winsockp.h"
//
// GETSOCKNAME_HACK turns on a hack where instead of returning INADDR_ANY
// for AF_INET sockets, it returns one of ths host's actual IP
// addresses.
//
#define GETSOCKNAME_HACK 0
#if GETSOCKNAME_HACK
IN_ADDR
GetHostIpAddress (
VOID
);
#endif
int
WSPAPI
WSPGetPeerName (
IN SOCKET Handle,
OUT struct sockaddr * SocketAddress,
OUT int *SocketAddressLength,
OUT LPINT lpErrno
)
/*++
Routine Description:
getpeername() retrieves the name of the peer connected to the socket
s and stores it in the struct sockaddr identified by name. It is
used on a connected datagram or stream socket.
On return, the namelen argument contains the actual size of the name
returned in bytes.
Arguments:
s - A descriptor identifying a connected socket.
name - The structure which is to receive the name of the peer.
namelen - A pointer to the size of the name structure.
Return Value:
If no error occurs, getpeername() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code may be retrieved
by calling WSAGetLastError().
--*/
{
PSOCKET_INFORMATION socket = NULL;
int err;
WS_ENTER( "getpeername", (PVOID)Handle, SocketAddress, SocketAddressLength, NULL );
WS_ASSERT( lpErrno != NULL );
err = SockEnterApi( TRUE, TRUE, FALSE );
if( err != NO_ERROR ) {
WS_EXIT( "getpeername", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Find a pointer to the socket structure corresponding to the
// passed-in handle.
//
socket = SockFindAndReferenceSocket( Handle, TRUE );
if ( socket == NULL ) {
err = WSAENOTSOCK;
goto exit;
}
//
// Acquire the lock that protects the socket.
//
SockAcquireSocketLockExclusive( socket );
//
// If the socket is not in a connected state then this is not a
// legal request.
//
if ( socket->State != SocketStateConnected ) {
err = WSAENOTCONN;
goto exit;
}
//
// Make sure that the specified address buffer is large enough.
//
if ( socket->RemoteAddressLength > *SocketAddressLength ) {
err = WSAEFAULT;
goto exit;
}
//
// Copy over the remote socket's name into the output buffer.
//
RtlCopyMemory(
SocketAddress,
socket->RemoteAddress,
socket->RemoteAddressLength
);
*SocketAddressLength = socket->RemoteAddressLength;
exit:
IF_DEBUG(GETNAME) {
if ( err != NO_ERROR ) {
WS_PRINT(( "getpeername on socket %lx (%lx) failed: %ld.\n",
Handle, socket, err ));
} else {
WS_PRINT(( "getpeername on socket %lx (%lx) addr",
Handle, socket ));
WsPrintSockaddr( socket->RemoteAddress, &socket->RemoteAddressLength );
}
}
if ( socket != NULL ) {
SockReleaseSocketLock( socket );
SockDereferenceSocket( socket );
}
if ( err != NO_ERROR ) {
WS_EXIT( "getpeername", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
WS_EXIT( "getpeername", NO_ERROR, FALSE );
return NO_ERROR;
} // WSPGetPeerName
int
WSPAPI
WSPGetSockName (
IN SOCKET Handle,
OUT struct sockaddr *SocketAddress,
OUT int *SocketAddressLength,
OUT LPINT lpErrno
)
/*++
Routine Description:
getsockname() retrieves the current name for the specified socket
descriptor in name. It is used on a bound and/or connected socket
specified by the s parameter. The local association is returned.
This call is especially useful when a connect() call has been made
without doing a bind() first; this call provides the only means by
which you can determine the local association which has been set by
the system.
On return, the namelen argument contains the actual size of the name
returned in bytes.
Arguments:
s - A descriptor identifying a bound socket.
name - The name of the socket.
namelen - The size of the name array.
Return Value:
If no error occurs, getsockname() returns 0. Otherwise, a value of
SOCKET_ERROR is returned, and a specific error code may be retrieved
by calling WSAGetLastError().
--*/
{
PSOCKET_INFORMATION socket;
int err;
PTRANSPORT_ADDRESS tdiAddress;
ULONG tdiAddressLength;
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
UCHAR tdiAddressBuffer[MAX_FAST_TDI_ADDRESS];
WS_ENTER( "getsockname", (PVOID)Handle, SocketAddress, SocketAddressLength, NULL );
WS_ASSERT( lpErrno != NULL );
err = SockEnterApi( TRUE, TRUE, FALSE );
if( err != NO_ERROR ) {
WS_EXIT( "getpeername", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Initialize locals so we know how to clean up on exit.
//
tdiAddress = NULL;
//
// Find a pointer to the socket structure corresponding to the
// passed-in handle.
//
socket = SockFindAndReferenceSocket( Handle, TRUE );
if ( socket == NULL ) {
err = WSAENOTSOCK;
goto exit;
}
//
// Acquire the lock that protects the socket.
//
SockAcquireSocketLockExclusive( socket );
//
// If the socket has not been bound, then this is not a valid
// call.
if ( socket->State == SocketStateOpen ) {
err = WSAEINVAL;
goto exit;
}
//
// Allocate enough space to hold the TDI address structure we'll pass
// to AFD.
//
tdiAddressLength = socket->HelperDll->MaxTdiAddressLength;
if( tdiAddressLength <= sizeof(tdiAddressBuffer) ) {
tdiAddress = (PVOID)tdiAddressBuffer;
} else {
tdiAddress = ALLOCATE_HEAP( tdiAddressLength + 4 );
if ( tdiAddress == NULL ) {
err = WSAENOBUFS;
goto exit;
}
}
//
// Get the actual address we bound to. It is possible on some
// transports to partially specify an address, in which case the
// transport will assign an address for use. This IOCTL obtains the
// real address for the endpoint. Note that we can't just use the
// address stored in the socket, as this can change due to
// a connect() or other operation.
//
status = NtDeviceIoControlFile(
(HANDLE)socket->Handle,
SockThreadEvent,
NULL, // APC Routine
NULL, // APC Context
&ioStatusBlock,
IOCTL_AFD_GET_ADDRESS,
NULL,
0,
tdiAddress,
tdiAddressLength + 4
);
if ( status == STATUS_PENDING ) {
SockReleaseSocketLock( socket );
SockWaitForSingleObject(
SockThreadEvent,
socket->Handle,
SOCK_NEVER_CALL_BLOCKING_HOOK,
SOCK_NO_TIMEOUT
);
SockAcquireSocketLockExclusive( socket );
status = ioStatusBlock.Status;
}
if ( !NT_SUCCESS(status) ) {
err = SockNtStatusToSocketError( status );
WS_ASSERT( !"Unexpected NtDeviceIoControlFile failure" );
goto exit;
}
//
// Convert the actual address that was bound to this socket to the
// sockaddr format in order to store it.
//
SockBuildSockaddr(
socket->LocalAddress,
&socket->LocalAddressLength,
(PTRANSPORT_ADDRESS)( (PCHAR)tdiAddress + 4 )
);
//
// Make sure that the specified address buffer is large enough.
//
if ( socket->LocalAddressLength > *SocketAddressLength ) {
err = WSAEFAULT;
goto exit;
}
//
// Copy over the socket's address into the output buffer.
//
RtlCopyMemory(
SocketAddress,
socket->LocalAddress,
socket->LocalAddressLength
);
*SocketAddressLength = socket->LocalAddressLength;
#if GETSOCKNAME_HACK
// !!! HACK--if ip addr == 0 convert to one of the host's IP addresses.
if ( SocketAddress->sa_family == AF_INET ) {
PSOCKADDR_IN sockaddrIn = (PSOCKADDR_IN)SocketAddress;
if ( sockaddrIn->sin_addr.s_addr == INADDR_ANY ) {
sockaddrIn->sin_addr = GetHostIpAddress( );
}
}
#endif
exit:
IF_DEBUG(GETNAME) {
if ( err != NO_ERROR ) {
WS_PRINT(( "getsockname on socket %lx (%lx) failed: %ld.\n",
Handle, socket, err ));
} else {
WS_PRINT(( "getsockname on socket %lx (%lx) addr",
Handle, socket ));
WsPrintSockaddr( socket->LocalAddress, &socket->LocalAddressLength );
}
}
if ( socket != NULL ) {
SockReleaseSocketLock( socket );
SockDereferenceSocket( socket );
}
if ( tdiAddress != NULL && tdiAddress != (PVOID)tdiAddressBuffer ) {
FREE_HEAP( tdiAddress );
}
if ( err != NO_ERROR ) {
WS_EXIT( "getsockname", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
WS_EXIT( "getsockname", NO_ERROR, FALSE );
return NO_ERROR;
} // WSPGetSockName
#if GETSOCKNAME_HACK
IN_ADDR
GetHostIpAddress (
VOID
)
{
HKEY tcpipKey;
HKEY adapterKey;
DWORD error;
IN_ADDR in;
DWORD bindListLength;
PWSTR bindList;
ULONG type;
PWSTR adapterName;
WCHAR adapterRegKeyName[256];
CHAR ipAddress[32];
DWORD ipAddressLength = 32;
in.s_addr = INADDR_ANY;
error = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services\\TcpIp\\Linkage",
0,
KEY_READ,
&tcpipKey
);
if ( error != NO_ERROR ) {
IF_DEBUG(GETNAME) {
WS_PRINT(( "GetHostIpAddress: RegOpenKeyExW failed: %ld\n", error ));
}
return in;
}
bindListLength = 0;
error = RegQueryValueExW(
tcpipKey,
L"Bind",
NULL,
&type,
NULL,
(LPDWORD)&bindListLength
);
if ( error != ERROR_MORE_DATA && error != NO_ERROR ) {
IF_DEBUG(GETNAME) {
WS_PRINT(( "GetHostIpAddress: RegQueryValueEx(1) failed: %ld\n",
error ));
}
RegCloseKey( tcpipKey );
return in;
}
bindList = ALLOCATE_HEAP( bindListLength );
if ( bindList == NULL ) {
RegCloseKey( tcpipKey );
return in;
}
error = RegQueryValueExW(
tcpipKey,
L"Bind",
NULL,
&type,
(PVOID)bindList,
&bindListLength
);
if ( error != NO_ERROR ) {
IF_DEBUG(GETNAME) {
WS_PRINT(( "GetHostIpAddress: RegQueryValueEx(2) failed: %ld\n",
error ));
}
RegCloseKey( tcpipKey );
FREE_HEAP( bindList );
return in;
}
adapterName = bindList + wcslen( bindList );
while ( *adapterName != '\\' ) {
adapterName--;
}
adapterName++;
RegCloseKey( tcpipKey );
wcscpy( adapterRegKeyName, L"System\\CurrentControlSet\\Services\\" );
wcscat( adapterRegKeyName, adapterName );
wcscat( adapterRegKeyName, L"\\Parameters\\Tcpip" );
error = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
adapterRegKeyName,
0,
KEY_READ,
&adapterKey
);
if ( error != NO_ERROR ) {
IF_DEBUG(GETNAME) {
WS_PRINT(( "GetHostIpAddress: RegOpenKeyExW(2) failed: %ld\n", error ));
}
return in;
}
FREE_HEAP( bindList );
error = RegQueryValueExA(
adapterKey,
"IPAddress",
NULL,
&type,
(PVOID)ipAddress,
&ipAddressLength
);
if ( error != NO_ERROR ) {
IF_DEBUG(HELPER_DLL) {
WS_PRINT(( "GetHostIpAddress: RegQueryValueEx(3) failed: %ld\n",
error ));
}
return in;
}
RegCloseKey( adapterKey );
in.s_addr = inet_addr( ipAddress );
return in;
} // GetHostIpAddress
#endif