/*!
 * @file remote.h
 * @brief Declarations of functions and types that interact with a remote endpoint.
 */
#ifndef _METERPRETER_COMMON_REMOTE_H
#define _METERPRETER_COMMON_REMOTE_H

#include "common_thread.h"
#include "common_config.h"
#include "common_pivot_tree.h"

/*! @brief This is the size of the certificate hash that is validated (sha1) */
#define CERT_HASH_SIZE 20

typedef wchar_t CHARTYPE;
typedef CHARTYPE* STRTYPE;

// Forward declarations required to keep compilers happy.
typedef struct _Packet Packet;
typedef struct _PacketRequestCompletion PacketRequestCompletion;
typedef struct _Transport Transport;
typedef struct _SslLib SslLib;
typedef struct _Remote Remote;
typedef struct _TimeoutSettings TimeoutSettings;
typedef struct _HttpTransportContext HttpTransportContext;
typedef struct _PacketEncryptionContext PacketEncryptionContext;

typedef UINT_PTR(*PTransportGetHandle)(Transport* transport);
typedef DWORD(*PTransportGetConfigSize)(Transport* transport);
typedef void(*PTransportSetHandle)(Transport* transport, UINT_PTR handle);
typedef void(*PTransportReset)(Transport* transport, BOOL shuttingDown);
typedef DWORD(*PTransportInit)(Transport* transport);
typedef DWORD(*PTransportDeinit)(Transport* transport);
typedef void(*PTransportDestroy)(Transport* transport);
typedef DWORD(*PTransportGetMigrateContext)(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, LPBYTE* contextBuffer);
typedef Transport*(*PTransportCreate)(Remote* remote, MetsrvTransportCommon* config, LPDWORD size);
typedef void(*PTransportRemove)(Remote* remote, Transport* oldTransport);
typedef void(*PConfigCreate)(Remote* remote, LPBYTE uuid, MetsrvConfig** config, LPDWORD size);

typedef DWORD(*PServerDispatch)(Remote* remote, THREAD* dispatchThread);
typedef DWORD(*PPacketTransmit)(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength);

typedef HANDLE(*PCreateHttpRequest)(HttpTransportContext* ctx, BOOL isGet, const char* direction);
typedef BOOL(*PSendHttpRequest)(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size);
typedef BOOL(*PCloseRequest)(HANDLE hReq);
typedef DWORD(*PValidateResponse)(HANDLE hReq, HttpTransportContext* ctx);
typedef BOOL(*PReceiveResponse)(HANDLE hReq);
typedef BOOL(*PReadResponse)(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead);

typedef struct _TimeoutSettings
{
	/*! @ brief The total number of seconds to wait for a new packet before killing off the session. */
	int comms;
	/*! @ brief The total number of seconds to keep retrying for before a new session is established. */
	UINT retry_total;
	/*! @ brief The number of seconds to wait between reconnects. */
	UINT retry_wait;
} TimeoutSettings;

typedef struct _TcpTransportContext
{
	SOCKET fd;                            ///! Remote socket file descriptor.
	SOCKET listen;                        ///! Listen socket descriptor, if any.
} TcpTransportContext;

typedef struct _NamedPipeTransportContext
{
	STRTYPE pipe_name;                    ///! Name of the pipe in '\\<server>\<name>' format
	HANDLE pipe;                          ///! Reference to the named pipe handle.
	LOCK* write_lock;                     ///! Reference to the thread write lock.
} NamedPipeTransportContext;

typedef struct _HttpTransportContext
{
	BOOL ssl;                             ///! Flag indicating whether the connection uses SSL.
	HANDLE internet;                      ///! Handle to the internet module for use with HTTP and HTTPS.
	HANDLE connection;                    ///! Handle to the HTTP or HTTPS connection.
	unsigned char* cert_hash;             ///! Pointer to the 20-byte certificate hash to validate

	CSTRTYPE url;                         ///! Pointer to the URL stored with the transport.
	STRTYPE ua;                           ///! User agent string.
	STRTYPE uri;                          ///! UUID encoded as a URI.
	STRTYPE new_uri;                      ///! New URI for stageless URI switches
	STRTYPE proxy;                        ///! Proxy details.
	STRTYPE proxy_user;                   ///! Proxy username.
	STRTYPE proxy_pass;                   ///! Proxy password.
	STRTYPE custom_headers;               ///! List of custom headers to add to outgoing requests.

	BOOL proxy_configured;                ///! Indication of whether the proxy has been configured.
	LPVOID proxy_for_url;                 ///! Pointer to the proxy for the current url (if required).

	BOOL move_to_wininet;                 ///! If set, winhttp is busted, and we need to move to wininet.

	PCreateHttpRequest create_req;        ///! WinHTTP/WinINET specific request creation.
	PSendHttpRequest send_req;            ///! WinHTTP/WinINET specifc request sending.
	PCloseRequest close_req;              ///! WinHTTP/WinINET specifc request closing.
	PValidateResponse validate_response;  ///! WinHTTP/WinINET specific response validation.
	PReceiveResponse receive_response;    ///! WinHttp/WinINET specific response data reception.
	PReadResponse read_response;          ///! WinHttp/WinINET specific response data reading.
} HttpTransportContext;

typedef struct _Transport
{
	DWORD type;                           ///! The type of transport in use.
	PTransportGetHandle get_handle;       ///! Function to get the socket/handle from the transport.
	PTransportSetHandle set_handle;       ///! Function to set the socket/handle on the transport.
	PTransportGetConfigSize get_config_size; ///! Function to get the size of the configuration for the transport.
	PTransportReset transport_reset;      ///! Function to reset/clean the transport ready for restarting.
	PTransportInit transport_init;        ///! Initialises the transport.
	PTransportDeinit transport_deinit;    ///! Deinitialises the transport.
	PTransportDestroy transport_destroy;  ///! Destroy the transport.
	PServerDispatch server_dispatch;      ///! Transport dispatch function.
	PPacketTransmit packet_transmit;      ///! Transmits a packet over the transport.
	PTransportGetMigrateContext get_migrate_context; ///! Creates a migrate context that is transport-specific.
	STRTYPE url;                          ///! Full URL describing the comms in use.
	VOID* ctx;                            ///! Pointer to the type-specific transport context;
	TimeoutSettings timeouts;             ///! Container for the timeout settings.
	int comms_last_packet;                ///! Unix timestamp of the last packet received.
	struct _Transport* next_transport;    ///! Pointer to the next transport in the list.
	struct _Transport* prev_transport;    ///! Pointer to the previous transport in the list.
} Transport;

/*!
 * @brief Remote context allocation.
 * @details Wraps the initialized file descriptor for extension purposes.
 *          A \c Remote is effectively a pointer to a remote client context
 *          which contains magic pixie dust that identifies the connection
 *          along with a way to interact with it.
 * @remark The `Original` and `Current` members are used to allow for
 *         functionality such as `rev2self` and reverting back to the initial
 *         desktop stations/desktops.
 */
typedef struct _Remote
{
	PConfigCreate config_create;          ///! Pointer to the function that will create a configuration block from the curren setup.

	Transport* transport;                 ///! Pointer to the currently used transport mechanism in a circular list of transports
	Transport* next_transport;            ///! Set externally when transports are requested to be changed.
	DWORD next_transport_wait;            ///! Number of seconds to wait before going to the next transport (used for sleeping).

	MetsrvConfig* orig_config;            ///! Pointer to the original configuration.

	LOCK* lock;                           ///! General transport usage lock (used by SSL, and desktop stuff too).

	HANDLE server_thread;                 ///! Handle to the current server thread.
	HANDLE server_token;                  ///! Handle to the current server security token.
	HANDLE thread_token;                  ///! Handle to the current thread security token.

	DWORD orig_sess_id;                   ///! ID of the original Meterpreter session.
	DWORD curr_sess_id;                   ///! ID of the currently active session.
	char* orig_station_name;              ///! Original station name.
	char* curr_station_name;              ///! Name of the current station.

	char* orig_desktop_name;              ///! Original desktop name.
	char* curr_desktop_name;              ///! Name of the current desktop.

	PTransportCreate trans_create;        ///! Helper to create transports from configuration.
	PTransportRemove trans_remove;        ///! Helper to remove transports from the current session.

	int sess_expiry_time;                 ///! Number of seconds that the session runs for.
	int sess_expiry_end;                  ///! Unix timestamp for when the server should shut down.
	int sess_start_time;                  ///! Unix timestamp representing the session startup time.

	PivotTree* pivot_sessions;            ///! Collection of active Meterpreter session pivots.
	PivotTree* pivot_listeners;           ///! Collection of active Meterpreter pivot listeners.

	PacketEncryptionContext* enc_ctx;     ///! Reference to the packet encryption context.
} Remote;

#endif