Beispiel #1
0
/*
 * Create a response packet from a request, referencing the requestors 
 * message identifier.
 */
Packet *packet_create_response(Packet *request)
{
	Packet *response = NULL;
	Tlv method, requestId;
	BOOL success = FALSE;
	PacketTlvType responseType;

	if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST)
		responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE;
	else
		responseType = PACKET_TLV_TYPE_RESPONSE;

	do
	{
		// Get the request TLV's method
		if (packet_get_tlv_string(request, TLV_TYPE_METHOD,
				&method) != ERROR_SUCCESS)
			break;

		// Try to allocate a response packet
		if (!(response = packet_create(responseType,
				(PCHAR)method.buffer)))
			break;

		// Get the request TLV's request identifier
		if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID,
				&requestId) != ERROR_SUCCESS)
			break;

		// Add the request identifier to the packet
		packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID,
				(PCHAR)requestId.buffer);

		success = TRUE;

	} while (0);

	// Cleanup on failure
	if (!success)
	{
		if (response)
			packet_destroy(response);

		response = NULL;
	}

	return response;
}
Beispiel #2
0
/*
 * Get the value of a string TLV
 */
PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type)
{
	Tlv stringTlv;
	PCHAR string = NULL;

	if (packet_get_tlv_string(packet, type, &stringTlv) == ERROR_SUCCESS)
		string = (PCHAR)stringTlv.buffer;

	return string;
}
Beispiel #3
0
/*!
 * @brief Call the register completion handler(s) for the given request identifier.
 * @details Only those handlers that match the given request are executed.
 * @param remote Pointer to the \c Remote instance for this call.
 * @param response Pointer to the response \c Packet.
 * @param requestId ID of the request to execute the completion handlers of.
 * @return Indication of success or failure.
 * @retval ERROR_NOT_FOUND Unable to find any matching completion handlers for the request.
 * @retval ERROR_SUCCESS Execution was successful.
 */
DWORD packet_call_completion_handlers( Remote *remote, Packet *response, LPCSTR requestId )
{
	PacketCompletionRoutineEntry *current;
	DWORD result = packet_get_tlv_value_uint(response, TLV_TYPE_RESULT);
	DWORD matches = 0;
	Tlv methodTlv;
	LPCSTR method = NULL;

	// Get the method associated with this packet
	if (packet_get_tlv_string(response, TLV_TYPE_METHOD, &methodTlv) == ERROR_SUCCESS)
	{
		method = (LPCSTR)methodTlv.buffer;
	}

	// Enumerate the completion routine list
	for (current = packetCompletionRoutineList; current; current = current->next)
	{
		// Does the request id of the completion entry match the packet's request
		// id?
		if (strcmp(requestId, current->requestId))
		{
			continue;
		}

		// Call the completion routine
		current->handler.routine(remote, response, current->handler.context, method, result);

		// Increment the number of matched handlers
		matches++;
	}

	if (matches)
	{
		packet_remove_completion_handler(requestId);
	}

	return (matches > 0) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
}
Beispiel #4
0
/*!
 * @brief Create a response packet from a request.
 * @details Create a response packet from a request, referencing the requestors
 * message identifier.
 * @param request The request \c Packet to build a response for.
 * @return Pointer to a new \c Packet.
 */
Packet *packet_create_response(Packet *request)
{
	Packet *response = NULL;
	Tlv method, requestId;
	BOOL success = FALSE;
	PacketTlvType responseType;

	if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST)
	{
		responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE;
	}
	else
	{
		responseType = PACKET_TLV_TYPE_RESPONSE;
	}

	do
	{
		// Get the request TLV's method
		if (packet_get_tlv_string(request, TLV_TYPE_METHOD, &method) != ERROR_SUCCESS)
		{
			break;
		}

		// Try to allocate a response packet
		if (!(response = packet_create(responseType, (PCHAR)method.buffer)))
		{
			break;
		}

		// Get the request TLV's request identifier
		if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS)
		{
			break;
		}

		// Add the request identifier to the packet
		packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID, (PCHAR)requestId.buffer);

		// If the packet that is being handled is considered local, then we
		// associate the response with the request so that it can be handled
		// locally (and vice versa)
		if (request->local)
		{
			request->partner = response;
			response->partner = request;
		}

		success = TRUE;

	} while (0);

	// Cleanup on failure
	if (!success)
	{
		if (response)
		{
			packet_destroy(response);
		}

		response = NULL;
	}

	return response;
}
Beispiel #5
0
/*
 * Transmit and destroy a packet
 */
DWORD packet_transmit(Remote *remote, Packet *packet, 
		PacketRequestCompletion *completion)
{
	CryptoContext *crypto;
	Tlv requestId;
	DWORD res;
	DWORD idx;
#ifdef _UNIX
	int local_error = -1;
#endif	

	// If the packet does not already have a request identifier, create
	// one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
			&requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid) - 1] = 0;

		for (index = 0; 
		     index < sizeof(rid) - 1; 
		     index++)
			rid[index] = (rand() % 0x5e) + 0x21;

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request 
		// identifier, insert the completion routine into the list
		if ((completion) &&
		    (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				&requestId) == ERROR_SUCCESS))
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload, 
					packet->payloadLength, &packet->payload, 
					&packet->payloadLength)) !=
					ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

		idx = 0;
		while( idx < sizeof(packet->header)) { 
			// Transmit the packet's header (length, type)
			res = SSL_write(
				remote->ssl, 
				(LPCSTR)(&packet->header) + idx, 
				sizeof(packet->header) - idx
			);
				
			if(res <= 0) {
				dprintf("transmit header failed with return %d at index %d\n", res, idx);
				break;
			}
			idx += res;
		}
		if(res < 0) break;

		idx = 0;
		while( idx < packet->payloadLength) { 
			// Transmit the packet's payload (length, type)
			res = SSL_write(
				remote->ssl, 
				packet->payload + idx,
				packet->payloadLength - idx
			);
			if(res < 0)
				break;

			idx += res;
		}
		if(res < 0) {
			dprintf("transmit header failed with return %d at index %d\n", res, idx);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();
	
	// Destroy the packet
	packet_destroy(packet);

	return res;
}
/*!
 * @brief Transmit a packet via SSL _and_ destroy it.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to the \c Packet that is to be sent.
 * @param completion Pointer to the completion routines to process.
 * @return An indication of the result of processing the transmission request.
 * @remark This uses an SSL-encrypted TCP channel, and does not imply the use of HTTPS.
 */
DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion)
{
	CryptoContext* crypto;
	Tlv requestId;
	DWORD res;
	DWORD idx;
	TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;

	lock_acquire(remote->lock);

	// If the packet does not already have a request identifier, create one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid)-1] = 0;

		for (index = 0; index < sizeof(rid)-1; index++)
		{
			rid[index] = (rand() % 0x5e) + 0x21;
		}

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request
		// identifier, insert the completion routine into the list
		if ((completion) &&
			(packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
			&requestId) == ERROR_SUCCESS))
		{
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);
		}

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
			(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
			(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload,
				packet->payloadLength, &packet->payload,
				&packet->payloadLength)) !=
				ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

		dprintf("[PACKET] New xor key for sending");
		packet->header.xor_key = rand_xor_key();
		// before transmission, xor the whole lot, starting with the body
		xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength);
		// then the header
		xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8);
		// be sure to switch the xor header before writing
		packet->header.xor_key = htonl(packet->header.xor_key);

		idx = 0;
		while (idx < sizeof(packet->header))
		{
			// Transmit the packet's header (length, type)
			res = SSL_write(
				ctx->ssl,
				(LPCSTR)(&packet->header) + idx,
				sizeof(packet->header) - idx
				);

			if (res <= 0)
			{
				dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
				break;
			}
			idx += res;
		}

		if (res < 0)
		{
			break;
		}

		idx = 0;
		while (idx < packet->payloadLength)
		{
			// Transmit the packet's payload (length, type)
			res = SSL_write(
				ctx->ssl,
				packet->payload + idx,
				packet->payloadLength - idx
				);

			if (res < 0)
			{
				break;
			}

			idx += res;
		}

		if (res < 0)
		{
			dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();

	// Destroy the packet
	packet_destroy(packet);

	lock_release(remote->lock);

	return res;
}
Beispiel #7
0
/*!
 * @brief Process a single command in a seperate thread of execution.
 * @param thread Pointer to the thread to execute.
 * @return Result of processing.
 */
DWORD THREADCALL command_process_thread( THREAD * thread )
{
	DWORD index       = 0;
	DWORD result      = ERROR_SUCCESS;
	Tlv methodTlv     = {0};
	Tlv requestIdTlv  = {0};
	PCHAR method      = NULL;
	PCHAR requestId   = NULL;
	Command * current = NULL;
	Remote * remote   = NULL;
	Packet * packet   = NULL;

	if( thread == NULL )
		return ERROR_INVALID_HANDLE;

	remote = (Remote *)thread->parameter1;
	if( remote == NULL )
		return ERROR_INVALID_HANDLE;

	packet = (Packet *)thread->parameter2;
	if( packet == NULL )
		return ERROR_INVALID_DATA;

	if( commandThreadList == NULL )
	{
		commandThreadList = list_create();
		if( commandThreadList == NULL )
			return ERROR_INVALID_HANDLE;
#ifndef _WIN32
		pthread_t tid;
		pthread_create(&tid, NULL, reap_zombie_thread, NULL);
		dprintf("reap_zombie_thread created, thread_id : 0x%x",tid);
#endif
	}

	list_add( commandThreadList, thread );

	__try
	{
		do
		{

			// Extract the method
			result = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
			if( result != ERROR_SUCCESS )
				break;

			dprintf( "[COMMAND] Processing method %s", methodTlv.buffer );

#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)", methodTlv.buffer, GetLastError());
				}
			}
#endif

			// Get the request identifier if the packet has one.
			result = packet_get_tlv_string( packet, TLV_TYPE_REQUEST_ID, &requestIdTlv );
			if( result == ERROR_SUCCESS )
				requestId = (PCHAR)requestIdTlv.buffer;

			method = (PCHAR)methodTlv.buffer;

			result = ERROR_NOT_FOUND;

			// Try to find a match in the dispatch type
			for( index = 0, result = ERROR_NOT_FOUND ; result == ERROR_NOT_FOUND && commands[index].method ; index++ )
			{
				if( strcmp( commands[index].method, method ) )
					continue;

				// Call the base handler
				result = command_call_dispatch( &commands[index], remote, packet );
			}

			// Regardless of error code, try to see if someone has overriden a base handler
			for( current = extension_commands, result = ERROR_NOT_FOUND ; 
				result == ERROR_NOT_FOUND && current && current->method ; current = current->next )
			{
				if( strcmp( current->method, method ) )
					continue;

				// Call the custom handler
				result = command_call_dispatch( current, remote, packet );
			}

			dprintf("[COMMAND] Calling completion handlers...");
			// Finally, call completion routines for the provided identifier
			if( ((packet_get_type(packet) == PACKET_TLV_TYPE_RESPONSE) || (packet_get_type(packet) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && (requestId))
				packet_call_completion_handlers( remote, packet, requestId );

			// If we get here, we're successful.
			result = ERROR_SUCCESS;

		} while( 0 );
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		dprintf("[COMMAND] Exception hit in command thread 0x%08X!", thread );
	}

	packet_destroy( packet );

	if( list_remove( commandThreadList, thread ) )
		thread_destroy( thread );

	return ERROR_SUCCESS;
}
Beispiel #8
0
/*
 * Transmit and destroy a packet over HTTP(S)
 */
DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
	CryptoContext *crypto;
	Tlv requestId;
	DWORD res;
#ifdef _UNIX
	int local_error = -1;
#endif


	lock_acquire( remote->lock );

	// If the packet does not already have a request identifier, create one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,&requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid) - 1] = 0;

		for (index = 0; index < sizeof(rid) - 1; index++)
			rid[index] = (rand() % 0x5e) + 0x21;

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request 
		// identifier, insert the completion routine into the list
		if ((completion) &&
		    (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				&requestId) == ERROR_SUCCESS))
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload, 
					packet->payloadLength, &packet->payload, 
					&packet->payloadLength)) !=
					ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

#ifdef _WIN32
		dprintf("Transmitting packet of length %d to remote", packet->payloadLength);
		res = packet_transmit_via_http_wininet(remote, packet, completion);
#else
		// XXX: Implement non-windows HTTP delivery
#endif

		if(res < 0) {
			dprintf("[PACKET] transmit failed with return %d\n", res);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();

	// Destroy the packet
	packet_destroy(packet);

	lock_release( remote->lock );

	return res;
}