windows-nt/Source/XPSP1/NT/net/rras/ip/nath323/ldappx.h

1023 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 - 2000 Microsoft Corporation
Module Name:
ldappx.h
Abstract:
Declares abstract data types and constants used in LDAP portion of the H.323/LDAP proxy.
LDAP Proxy is designed as an addition to H.323 proxy. The main purpose of the
LDAP proxy is to maintain LDAP Address Translation Table, which is used to map
aliases of H.323 endpoints to their IP addresses. The proxy adds an entry when it
intercepts an LDAP PDU from a client to directory server, and the PDU matches all
predefined criteria.
Author(s): ArlieD, IlyaK 14-Jul-1999
Revision History:
07/14/1999 File creation Arlie Davis (ArlieD)
08/20/1999 Improvement of processing of LDAP Ilya Kleyman (IlyaK)
LDAP SearchRequests
12/20/1999 Added prediction of receive sizes in Ilya Kleyman (IlyaK)
non-interpretative data transfer mode
02/20/2000 Added expiration policy of the entries Ilya Kleyman (IlyaK)
in LDAP Address Translation Table
03/12/2000 Added support for multiple private and Ilya Kleyman (IlyaK)
multiple public interface for RRAS
--*/
#ifndef __h323ics_ldappx_h
#define __h323ics_ldappx_h
#define LDAP_PATH_EQUAL_CHAR '='
#define LDAP_PATH_SEP_CHAR ','
extern BOOLEAN NhIsLocalAddress (ULONG Address);
extern ULONG NhMapAddressToAdapter (ULONG Address);
typedef MessageID LDAP_MESSAGE_ID;
#define ASN_SEQUENCE_TAG 0x30
#define ASN_LONG_HEADER_BIT 0x80
#define ASN_MIN_HEADER_LEN 2 // This value is fixed
#define LDAP_STANDARD_PORT 389 // Well-known LDAP port
#define LDAP_ALTERNATE_PORT 1002 // Alternate (ILS) LDAP port
#define LDAP_BUFFER_RECEIVE_SIZE 0x400
#define LDAP_BUFFER_MAX_RECV_SIZE 0x80000UL // Limit on maximum one-time receive size
#define LDAP_MAX_TRANSLATION_TABLE_SIZE 100000 // Maximum number of entries in translation table
#define LDAP_MAX_CONNECTIONS 50000 // Maximum number of concurrent connections through the proxy
// data structures -------------------------------------------------------------------
class LDAP_SOCKET;
class LDAP_CONNECTION;
struct LDAP_TRANSLATION_ENTRY
{
// An entry in the LDAP Address Translation Table is
// to be identified by three components:
// 1. Registered alias
// 2. Registered address
// 3. Directory server the alias is registered with
// 4. Directory path on the server
//
// Currently only first three are used.
//
ANSI_STRING Alias; // Memory owned, use FreeAnsiString
ANSI_STRING DirectoryPath; // Memory owned, use FreeAnsiString
ANSI_STRING CN; // Subset of DirectoryPath, NOT owned, do NOT free
IN_ADDR ClientAddress;
SOCKADDR_IN ServerAddress;
DWORD TimeStamp; // In seconds, since the last machine reboot
void
FreeContents (
void
)
{
FreeAnsiString (&Alias);
FreeAnsiString (&DirectoryPath);
CN.Buffer = NULL;
}
HRESULT
IsRegisteredViaInterface (
IN DWORD InterfaceAddress, // host order
OUT BOOL *Result
);
};
class LDAP_TRANSLATION_TABLE :
public SIMPLE_CRITICAL_SECTION_BASE
{
// LDAP Address Translation Table is a serialized
// container for translation entries. The Table
// can conduct various types of searches, and has
// an expiration policy on old entries. The expiration
// is done by means of a periodic timer thread and
// timestamps on each entry. Entries are added when
// successful AddResponses are received in reply to
// valid AddRequests. Entries are refreshed when
// successful refresh SearchResponses are received for
// valid refresh SearchRequests (for NetMeeting); or when
// successful refresh ModifyResponses are received for
// valid refresh ModifyRequests (for Phone Dialer).
private:
DYNAMIC_ARRAY <LDAP_TRANSLATION_ENTRY> Array;
HANDLE GarbageCollectorTimerHandle;
BOOL IsEnabled;
private:
HRESULT
InsertEntryLocked (
IN ANSI_STRING * Alias,
IN ANSI_STRING * DirectoryPath,
IN IN_ADDR ClientAddress,
IN SOCKADDR_IN * ServerAddress,
IN DWORD TimeToLive // in seconds
);
HRESULT
FindEntryByPathServer (
IN ANSI_STRING * DirectoryPath,
IN SOCKADDR_IN * ServerAddress,
OUT LDAP_TRANSLATION_ENTRY ** ReturnTranslationEntry
);
HRESULT FindEntryByAliasServer (
IN ANSI_STRING * Alias,
IN SOCKADDR_IN * ServerAddress,
OUT LDAP_TRANSLATION_ENTRY ** ReturnTranslationEntry
);
public:
LDAP_TRANSLATION_TABLE (
void
);
~LDAP_TRANSLATION_TABLE (
void
);
HRESULT
Start (
void
);
void
Stop (
void
);
#if DBG
void
PrintTable (
void
);
#endif
#define LDAP_TRANSLATION_TABLE_GARBAGE_COLLECTION_PERIOD (10 * 60 * 1000) // Milliseconds
#define LDAP_TRANSLATION_TABLE_ENTRY_INITIAL_TIME_TO_LIVE (10 * 60) // Seconds
static
void
GarbageCollectorCallback (
IN PVOID Context,
IN BOOLEAN TimerOrWaitFired
);
HRESULT
RefreshEntry (
IN ANSI_STRING * Alias,
IN ANSI_STRING * DirectoryPath,
IN IN_ADDR ClientAddress,
IN SOCKADDR_IN * ServerAddress,
IN DWORD TimeToLive
);
void
RemoveOldEntries (
void
);
HRESULT
QueryTableByAlias (
IN ANSI_STRING * Alias,
OUT IN_ADDR * ReturnClientAddress
);
HRESULT
QueryTableByCN (
IN ANSI_STRING * CN,
OUT IN_ADDR * ReturnClientAddress
);
HRESULT
QueryTableByAliasServer (
IN ANSI_STRING * Alias,
IN SOCKADDR_IN * ServerAddress,
OUT IN_ADDR * ReturnClientAddress
);
HRESULT
QueryTableByCNServer (
IN ANSI_STRING * CN,
IN SOCKADDR_IN * ServerAddress,
OUT IN_ADDR * ReturnClientAddress
);
HRESULT
InsertEntry (
IN ANSI_STRING * Alias,
IN ANSI_STRING * DirectoryPath,
IN IN_ADDR ClientAddress,
IN SOCKADDR_IN * ServerAddress,
IN DWORD TimeToLive // in seconds
);
HRESULT
RemoveEntry (
IN SOCKADDR_IN * ServerAddress,
IN ANSI_STRING * DirectoryPath
);
HRESULT
RemoveEntryByAliasServer (
IN ANSI_STRING * Alias,
IN SOCKADDR_IN * ServerAddress
);
void
OnInterfaceShutdown (
IN DWORD InterfaceAddress
);
BOOL
ReachedMaximumSize (
void
);
};
class LDAP_BUFFER
{
// LDAP_BUFFER is a simple structure
// that can hold raw data and be chained
// to other LDAP_BUFFERs
public:
LDAP_BUFFER (
void
);
~LDAP_BUFFER (
void
);
public:
DYNAMIC_ARRAY <BYTE> Data;
LIST_ENTRY ListEntry;
};
enum NOTIFY_REASON
{
SOCKET_SEND_COMPLETE,
SOCKET_RECEIVE_COMPLETE,
};
struct LDAP_OVERLAPPED
{
OVERLAPPED Overlapped;
BOOL IsPending;
DWORD BytesTransferred;
LDAP_SOCKET * Socket;
};
class LDAP_PUMP
{
friend class LDAP_CONNECTION;
friend class LDAP_SOCKET;
private:
LDAP_CONNECTION * Connection;
LDAP_SOCKET * Source;
LDAP_SOCKET * Dest;
// When set, the pump works in raw data
// transfer mode without modifications to
// the payload
BOOL IsPassiveDataTransfer;
public:
LDAP_PUMP (
IN LDAP_CONNECTION * ArgConnection,
IN LDAP_SOCKET * ArgSource,
IN LDAP_SOCKET * ArgDest
);
~LDAP_PUMP (
void
);
void Start (
void
);
void Stop (
void
);
// source is indicating that it has received data
void
OnRecvBuffer (
LDAP_BUFFER *
);
// destination is indicating that it has finished sending data
void
OnSendDrain (
void
);
void
SendQueueBuffer (
IN LDAP_BUFFER * Buffer
);
BOOL
CanIssueRecv (
void
);
void
Terminate (
void
);
void
EncodeSendMessage (
IN LDAPMessage * Message
);
void
StartPassiveDataTransfer (
void
);
BOOL IsActivelyPassingData (
void
) const;
};
class LDAP_SOCKET
{
// LDAP_SOCKET is a wrapper class
// around Windows asynchrounous socket.
// An instance of LDAP_SOCKET can
// asynchronously connect, send and receive
friend class LDAP_CONNECTION;
friend class LDAP_PUMP;
public:
enum STATE {
STATE_NONE,
STATE_ISSUING_CONNECT,
STATE_CONNECT_PENDING,
STATE_CONNECTED,
STATE_TERMINATED,
};
private:
SOCKADDR_IN ActualDestinationAddress;
SOCKADDR_IN RealSourceAddress;
BOOL IsNatRedirectActive;
LDAP_CONNECTION * LdapConnection;
LDAP_PUMP * RecvPump;
LDAP_PUMP * SendPump;
SOCKET Socket;
STATE State;
// receive state
LDAP_OVERLAPPED RecvOverlapped;
LDAP_BUFFER * RecvBuffer; // must be valid if RecvOverlapped.IsPending, must be null otherwise
DWORD RecvFlags;
LIST_ENTRY RecvBufferQueue; // contains LDAP_BUFFER.ListEntry
DWORD BytesToReceive;
SAMPLE_PREDICTOR <5> RecvSizePredictor;
// send stat
LDAP_OVERLAPPED SendOverlapped;
LDAP_BUFFER * SendBuffer; // must be valid if SendOverlapped.IsPending, must be null otherwise
LIST_ENTRY SendBufferQueue; // contains LDAP_BUFFER.ListEntry
// async connect state
HANDLE ConnectEvent;
HANDLE ConnectWaitHandle;
BOOL AttemptAnotherConnect;
private:
inline
void
Lock (
void
);
inline
void
Unlock (
void
);
inline
void
AssertLocked (
void
);
void
OnConnectCompletionLocked (
void
);
void
FreeConnectResources (
void
);
HRESULT
AttemptAlternateConnect (
void
);
void
OnIoComplete (
IN DWORD Status,
IN DWORD BytesTransferred,
IN LDAP_OVERLAPPED *
);
void
OnRecvComplete (
IN DWORD Status
);
void
OnSendComplete (
IN DWORD Status
);
void
RecvBuildBuffer (
IN LPBYTE Data,
IN DWORD Length
);
void DeleteBufferList (
IN LIST_ENTRY * ListHead
);
BOOL RecvRemoveBuffer (
OUT LDAP_BUFFER ** ReturnBuffer
);
// returns TRUE if a message was dequeued
BOOL SendNextBuffer (
void
);
public:
LDAP_SOCKET (
IN LDAP_CONNECTION * ArgLdapConnection,
IN LDAP_PUMP * ArgRecvPump,
IN LDAP_PUMP * ArgSendPump
);
~LDAP_SOCKET (
void
);
HRESULT
RecvIssue (
void
);
// may queue the buffer
void
SendQueueBuffer(
IN LDAP_BUFFER * Buffer
);
static
void
IoCompletionCallback (
IN DWORD Status,
IN DWORD Length,
IN LPOVERLAPPED Overlapped
);
static
void
OnConnectCompletion (
IN PVOID Context,
IN BOOLEAN TimerOrWaitFired
);
HRESULT
AcceptSocket (
IN SOCKET LocalClientSocket
);
HRESULT
IssueConnect (
IN SOCKADDR_IN * DestinationAddress
);
void
OnIoCompletion (
IN LDAP_BUFFER * Message,
IN DWORD Status,
IN DWORD BytesTransferred
);
void
Terminate (
void
);
STATE
GetState (void) {
AssertLocked ();
return State;
}
// retrieve the remote address of the connection
BOOL
GetRemoteAddress (
OUT SOCKADDR_IN * ReturnAddress
);
// retrieve the local address of the connection
BOOL
GetLocalAddress (
OUT SOCKADDR_IN * ReturnAddress
);
};
// this represents a single outstanding operation that the client has initiated.
enum LDAP_OPERATION_TYPE
{
LDAP_OPERATION_ADD,
LDAP_OPERATION_SEARCH,
LDAP_OPERATION_MODIFY,
LDAP_OPERATION_DELETE,
};
struct LDAP_OPERATION
{
// LDAP_OPERATIONs are created and queued when
// a client issues a request to the server.
// The actual processing of the operation
// starts when server sends back response
// with data and/or status code.
LDAP_MESSAGE_ID MessageID;
DWORD Type;
ANSI_STRING DirectoryPath; // owned by process heap
ANSI_STRING Alias; // owned by process heap
IN_ADDR ClientAddress;
SOCKADDR_IN ServerAddress;
DWORD EntryTimeToLive; // in seconds
void
FreeContents (
void
)
{
FreeAnsiString (&DirectoryPath);
FreeAnsiString (&Alias);
}
};
class LDAP_CONNECTION :
public SIMPLE_CRITICAL_SECTION_BASE,
public LIFETIME_CONTROLLER
{
// LDAP_CONNECTION represents two parts
// (public and private) of the connection
// being proxied by the LDAP proxy. In reflection
// of this it has easily distinguishable Server
// part and Client part
friend class LDAP_SOCKET;
public:
enum STATE {
STATE_NONE,
STATE_CONNECT_PENDING,
STATE_CONNECTED,
STATE_TERMINATED,
};
LIST_ENTRY ListEntry;
private:
LDAP_SOCKET ClientSocket;
LDAP_SOCKET ServerSocket;
DWORD SourceInterfaceAddress; // address of the interface on which the conection was accepted, host order
DWORD DestinationInterfaceAddress; // address of the interface on which the conection was accepted, host order
SOCKADDR_IN SourceAddress; // address of the source (originator of the connection)
SOCKADDR_IN DestinationAddress; // address of the destination (recipeint of the connection)
LDAP_PUMP PumpClientToServer;
LDAP_PUMP PumpServerToClient;
STATE State;
DYNAMIC_ARRAY <LDAP_OPERATION> OperationArray;
private:
void
StartIo (
void
);
BOOL
ProcessLdapMessage (
IN LDAP_PUMP * Pump,
IN LDAPMessage * LdapMessage
);
// client to server messages
BOOL
ProcessAddRequest (
IN LDAPMessage * Message
);
BOOL
ProcessModifyRequest (
IN LDAP_MESSAGE_ID MessageID,
IN ModifyRequest * Request
);
BOOL
ProcessDeleteRequest (
IN LDAP_MESSAGE_ID MessageID,
IN DelRequest * Request
);
BOOL
ProcessSearchRequest (
IN LDAPMessage * Message
);
// server to client messages
void
ProcessAddResponse (
IN LDAPMessage * Response
);
void
ProcessModifyResponse (
IN LDAP_MESSAGE_ID MessageID,
IN ModifyResponse * Response
);
void
ProcessDeleteResponse (
IN LDAP_MESSAGE_ID MessageID,
IN DelResponse * Response
);
BOOL
ProcessSearchResponse (
IN LDAPMessage * Message
);
BOOL
FindOperationIndexByMessageID (
IN LDAP_MESSAGE_ID MessageID,
OUT DWORD * ReturnIndex
);
BOOL
FindOperationByMessageID (
IN LDAP_MESSAGE_ID MessageID,
OUT LDAP_OPERATION ** ReturnOperation
);
static
INT
BinarySearchOperationByMessageID (
IN const LDAP_MESSAGE_ID * SearchKey,
IN const LDAP_OPERATION * Comparand
);
HRESULT
CreateOperation (
IN LDAP_OPERATION_TYPE Type,
IN LDAP_MESSAGE_ID MessageID,
IN ANSI_STRING * DirectoryPath,
IN ANSI_STRING * Alias,
IN IN_ADDR ClientAddress,
IN SOCKADDR_IN * ServerAddress,
IN DWORD EntryTimeToLive // in seconds
);
public:
LDAP_CONNECTION (
IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
);
~LDAP_CONNECTION (
void
);
HRESULT
Initialize (
IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
);
HRESULT
InitializeLocked (
IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
);
HRESULT
AcceptSocket (
IN SOCKET Socket,
IN SOCKADDR_IN * LocalAddress,
IN SOCKADDR_IN * RemoteAddress,
IN SOCKADDR_IN * ArgActualDestinationAddress
);
// process a given LDAP message buffer
// in the context of a given pump (direction)
void
ProcessBuffer (
IN LDAP_PUMP * Pump,
IN LDAP_BUFFER * Buffer
);
void
OnStateChange (
IN LDAP_SOCKET * NotifyingSocket,
IN LDAP_SOCKET::STATE NewState
);
void
Terminate (
void
);
void
TerminateExternal (
void
);
BOOL
IsConnectionThrough (
IN DWORD InterfaceAddress // host order
);
// safe, external version
STATE
GetState (
void
)
{
STATE ReturnState;
Lock ();
ReturnState = State;
Unlock ();
return ReturnState;
}
};
DECLARE_SEARCH_FUNC_CAST (LDAP_MESSAGE_ID, LDAP_OPERATION);
inline
void
LDAP_SOCKET::Lock (
void
)
{
LdapConnection -> Lock ();
}
inline
void
LDAP_SOCKET::Unlock (
void
)
{
LdapConnection -> Unlock ();
}
inline
void
LDAP_SOCKET::AssertLocked (
void
)
{
LdapConnection -> AssertLocked();
}
class LDAP_CONNECTION_ARRAY :
public SIMPLE_CRITICAL_SECTION_BASE {
private:
// Contains set/array of LDAP_CONNECTION references
DYNAMIC_ARRAY <LDAP_CONNECTION *> ConnectionArray;
// Controls whether or not the structure will accept
// new LDAP connections
BOOL IsEnabled;
public:
LDAP_CONNECTION_ARRAY (void);
HRESULT
InsertConnection (
IN LDAP_CONNECTION * LdapConnection
);
void
RemoveConnection (
IN LDAP_CONNECTION * LdapConnection
);
void
OnInterfaceShutdown (
IN DWORD InterfaceAddress // host order
);
void
Start (
void
);
void
Stop (
void
);
};
class LDAP_ACCEPT
{
private:
// Contain accept context
ASYNC_ACCEPT AsyncAcceptContext;
// Handles for dynamic redirects from the standard and
// alternate LDAP ports to the selected loopback port
HANDLE LoopbackRedirectHandle1;
HANDLE LoopbackRedirectHandle2;
private:
HRESULT
CreateBindSocket (
void
);
HRESULT
StartLoopbackNatRedirects (
void
);
void
StopLoopbackNatRedirects (
void
);
void
CloseSocket (
void
);
static
void
AsyncAcceptFunction (
IN PVOID Context,
IN SOCKET Socket,
IN SOCKADDR_IN * LocalAddress,
IN SOCKADDR_IN * RemoteAddress
);
static
HRESULT
LDAP_ACCEPT::AsyncAcceptFunctionInternal (
IN PVOID Context,
IN SOCKET Socket,
IN SOCKADDR_IN * LocalAddress,
IN SOCKADDR_IN * RemoteAddress
);
public:
LDAP_ACCEPT (
void
);
HRESULT
Start (
void
);
void
Stop(
void
);
};
class LDAP_CODER :
public SIMPLE_CRITICAL_SECTION_BASE
{
private:
ASN1encoding_t Encoder;
ASN1decoding_t Decoder;
public:
LDAP_CODER (
void
);
~LDAP_CODER (
void
);
DWORD
Start (
void
);
void
Stop (
void
);
ASN1error_e Decode (
IN LPBYTE Data,
IN DWORD Length,
OUT LDAPMessage ** ReturnPduStructure,
OUT DWORD * ReturnIndex
);
};
struct LDAP_PATH_ELEMENTS
{
ANSI_STRING CN;
ANSI_STRING C;
ANSI_STRING O;
ANSI_STRING ObjectClass;
};
struct LDAP_OBJECT_NAME_ELEMENTS
{
ANSI_STRING CN;
ANSI_STRING O;
ANSI_STRING OU;
};
extern SYNC_COUNTER LdapSyncCounter;
extern LDAP_CONNECTION_ARRAY LdapConnectionArray;
extern LDAP_TRANSLATION_TABLE LdapTranslationTable;
extern LDAP_CODER LdapCoder;
extern LDAP_ACCEPT LdapAccept;
extern SOCKADDR_IN LdapListenSocketAddress;
extern DWORD EnableLocalH323Routing;
HRESULT
LdapQueryTableByAlias (
IN ANSI_STRING * Alias,
OUT DWORD * ReturnClientAddress // host order
);
HRESULT
LdapQueryTableByAliasServer (
IN ANSI_STRING * Alias,
IN SOCKADDR_IN * ServerAddress,
OUT DWORD * ReturnClientAddress); // host order
#if DBG
void
LdapPrintTable (
void
);
#endif // DBG
#endif // __h323ics_ldappx_h