mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
libfreerdp/peer: initial protocol negotiation.
This commit is contained in:
@@ -31,6 +31,12 @@
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
enum CONNECTION_STATE
|
||||
{
|
||||
CONNECTION_STATE_INITIAL = 0,
|
||||
CONNECTION_STATE_NEGO
|
||||
};
|
||||
|
||||
boolean rdp_client_connect(rdpRdp* rdp);
|
||||
|
||||
#endif /* __CONNECTION_H */
|
||||
|
||||
@@ -269,6 +269,59 @@ int nego_recv(rdpTransport* transport, STREAM* s, void* extra)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive protocol security negotiation request message.\n
|
||||
* @param nego
|
||||
* @param s stream
|
||||
*/
|
||||
|
||||
boolean nego_recv_request(rdpNego* nego, STREAM* s)
|
||||
{
|
||||
uint8 li;
|
||||
uint8 c;
|
||||
uint8 type;
|
||||
|
||||
tpkt_read_header(s);
|
||||
li = tpdu_read_connection_request(s);
|
||||
if (li != stream_get_left(s) + 6)
|
||||
{
|
||||
printf("Incorrect TPDU length indicator.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (stream_get_left(s) > 8)
|
||||
{
|
||||
/* Optional routingToken or cookie, ending with CR+LF */
|
||||
while (stream_get_left(s) > 0)
|
||||
{
|
||||
stream_read_uint8(s, c);
|
||||
if (c != '\x0D')
|
||||
continue;
|
||||
stream_peek_uint8(s, c);
|
||||
if (c != '\x0A')
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_get_left(s) >= 8)
|
||||
{
|
||||
/* rdpNegData (optional) */
|
||||
|
||||
stream_read_uint8(s, type); /* Type */
|
||||
if (type != TYPE_RDP_NEG_REQ)
|
||||
{
|
||||
printf("Incorrect negotiation request type %d\n", type);
|
||||
return False;
|
||||
}
|
||||
|
||||
nego_process_negotiation_request(nego, s);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send protocol security negotiation message.
|
||||
* @param nego
|
||||
@@ -339,6 +392,26 @@ void nego_send_negotiation_request(rdpNego* nego)
|
||||
transport_write(nego->transport, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Negotiation Request from Connection Request message.
|
||||
* @param nego
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void nego_process_negotiation_request(rdpNego* nego, STREAM* s)
|
||||
{
|
||||
uint8 flags;
|
||||
uint16 length;
|
||||
|
||||
DEBUG_NEGO("RDP_NEG_REQ");
|
||||
|
||||
stream_read_uint8(s, flags);
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint32(s, nego->requested_protocols);
|
||||
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Negotiation Response from Connection Confirm message.
|
||||
* @param nego
|
||||
@@ -402,6 +475,41 @@ void nego_process_negotiation_failure(rdpNego* nego, STREAM* s)
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send RDP Negotiation Response (RDP_NEG_RSP).\n
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_send_negotiation_response(rdpNego* nego)
|
||||
{
|
||||
STREAM* s;
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
|
||||
s = stream_new(64);
|
||||
length = TPDU_CONNECTION_CONFIRM_LENGTH;
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek(s, length);
|
||||
|
||||
if (nego->selected_protocol > PROTOCOL_RDP)
|
||||
{
|
||||
/* RDP_NEG_DATA must be present for TLS and NLA */
|
||||
stream_write_uint8(s, TYPE_RDP_NEG_RSP);
|
||||
stream_write_uint8(s, EXTENDED_CLIENT_DATA_SUPPORTED); /* flags */
|
||||
stream_write_uint16(s, 8); /* RDP_NEG_DATA length (8) */
|
||||
stream_write_uint32(s, nego->selected_protocol); /* selectedProtocol */
|
||||
length += 8;
|
||||
}
|
||||
|
||||
stream_get_mark(s, em);
|
||||
stream_set_mark(s, bm);
|
||||
tpkt_write_header(s, length);
|
||||
tpdu_write_connection_confirm(s, length - 5);
|
||||
stream_set_mark(s, em);
|
||||
|
||||
transport_write(nego->transport, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize NEGO state machine.
|
||||
* @param nego
|
||||
|
||||
@@ -65,6 +65,8 @@ enum RDP_NEG_MSG
|
||||
TYPE_RDP_NEG_FAILURE = 0x3
|
||||
};
|
||||
|
||||
#define EXTENDED_CLIENT_DATA_SUPPORTED 0x01
|
||||
|
||||
extern char NEGO_STATE_STRINGS[6][25];
|
||||
extern char PROTOCOL_SECURITY_STRINGS[3][4];
|
||||
|
||||
@@ -92,10 +94,13 @@ void nego_attempt_rdp(rdpNego* nego);
|
||||
void nego_send(rdpNego* nego);
|
||||
int nego_recv(rdpTransport* transport, STREAM* s, void* extra);
|
||||
void nego_recv_response(rdpNego* nego);
|
||||
boolean nego_recv_request(rdpNego* nego, STREAM* s);
|
||||
|
||||
void nego_send_negotiation_request(rdpNego* nego);
|
||||
void nego_process_negotiation_request(rdpNego* nego, STREAM* s);
|
||||
void nego_process_negotiation_response(rdpNego* nego, STREAM* s);
|
||||
void nego_process_negotiation_failure(rdpNego* nego, STREAM* s);
|
||||
void nego_send_negotiation_response(rdpNego* nego);
|
||||
|
||||
rdpNego* nego_new(struct rdp_transport * transport);
|
||||
void nego_free(rdpNego* nego);
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
static boolean freerdp_peer_initialize(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
peer->state = CONNECTION_STATE_INITIAL;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -28,7 +32,7 @@ static boolean freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcou
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
rfds[*rcount] = (void*)(long)(peer->sockfd);
|
||||
rfds[*rcount] = (void*)(long)(peer->rdp->transport->tcp->sockfd);
|
||||
(*rcount)++;
|
||||
|
||||
return True;
|
||||
@@ -36,9 +40,78 @@ static boolean freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcou
|
||||
|
||||
static boolean freerdp_peer_check_fds(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
rdpRdp* rdp;
|
||||
int status;
|
||||
|
||||
rdp = (rdpRdp*) peer->rdp;
|
||||
|
||||
status = rdp_check_fds(rdp);
|
||||
if (status < 0)
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static int peer_process_connection_nego(rdpPeer* peer, STREAM* s)
|
||||
{
|
||||
if (!nego_recv_request(peer->rdp->nego, s))
|
||||
return -1;
|
||||
if (peer->rdp->nego->requested_protocols == PROTOCOL_RDP)
|
||||
{
|
||||
printf("Standard RDP encryption is not supported.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Requested protocols:");
|
||||
if ((peer->rdp->nego->requested_protocols | PROTOCOL_TLS))
|
||||
{
|
||||
printf(" TLS");
|
||||
if (peer->rdp->settings->tls_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
peer->rdp->nego->selected_protocol |= PROTOCOL_TLS;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
}
|
||||
if ((peer->rdp->nego->requested_protocols | PROTOCOL_NLA))
|
||||
{
|
||||
printf(" NLA");
|
||||
if (peer->rdp->settings->nla_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
peer->rdp->nego->selected_protocol |= PROTOCOL_NLA;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
nego_send_negotiation_response(peer->rdp->nego);
|
||||
|
||||
peer->state = CONNECTION_STATE_NEGO;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)extra;
|
||||
|
||||
switch (peer->state)
|
||||
{
|
||||
case CONNECTION_STATE_INITIAL:
|
||||
return peer_process_connection_nego(peer, s);
|
||||
|
||||
default:
|
||||
printf("Invalid state %d\n", peer->state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void freerdp_peer_disconnect(freerdp_peer* client)
|
||||
{
|
||||
}
|
||||
@@ -50,7 +123,6 @@ freerdp_peer* freerdp_peer_new(int sockfd)
|
||||
|
||||
client = xnew(freerdp_peer);
|
||||
|
||||
client->settings = settings_new();
|
||||
client->Initialize = freerdp_peer_initialize;
|
||||
client->GetFileDescriptor = freerdp_peer_get_fds;
|
||||
client->CheckFileDescriptor = freerdp_peer_check_fds;
|
||||
@@ -58,9 +130,16 @@ freerdp_peer* freerdp_peer_new(int sockfd)
|
||||
|
||||
peer = xnew(rdpPeer);
|
||||
peer->client = client;
|
||||
peer->sockfd = sockfd;
|
||||
peer->rdp = rdp_new(NULL);
|
||||
|
||||
client->peer = (void*)peer;
|
||||
client->settings = peer->rdp->settings;
|
||||
|
||||
transport_attach(peer->rdp->transport, sockfd);
|
||||
|
||||
peer->rdp->transport->recv_callback = peer_recv_callback;
|
||||
peer->rdp->transport->recv_extra = peer;
|
||||
transport_set_blocking_mode(peer->rdp->transport, False);
|
||||
|
||||
return client;
|
||||
}
|
||||
@@ -69,8 +148,8 @@ void freerdp_peer_free(freerdp_peer* client)
|
||||
{
|
||||
rdpPeer* peer = (rdpPeer*)client->peer;
|
||||
|
||||
rdp_free(peer->rdp);
|
||||
xfree(peer);
|
||||
settings_free(client->settings);
|
||||
xfree(client);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ struct rdp_peer
|
||||
{
|
||||
freerdp_peer* client;
|
||||
|
||||
int sockfd;
|
||||
rdpRdp* rdp;
|
||||
int state;
|
||||
};
|
||||
|
||||
#endif /* __PEER */
|
||||
|
||||
@@ -111,6 +111,28 @@ tpdu_write_header(STREAM* s, uint16 length, uint8 code)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Connection Request TPDU
|
||||
* @param s stream
|
||||
* @return length indicator (LI)
|
||||
*/
|
||||
|
||||
uint8 tpdu_read_connection_request(STREAM* s)
|
||||
{
|
||||
uint8 li;
|
||||
uint8 code;
|
||||
|
||||
li = tpdu_read_header(s, &code);
|
||||
|
||||
if (code != X224_TPDU_CONNECTION_REQUEST)
|
||||
{
|
||||
printf("Error: expected X224_TPDU_CONNECTION_REQUEST\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Connection Request TPDU.
|
||||
* @param s stream
|
||||
@@ -146,6 +168,18 @@ tpdu_read_connection_confirm(STREAM* s)
|
||||
return li;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Connection Confirm TPDU.
|
||||
* @param s stream
|
||||
* @param length TPDU length
|
||||
*/
|
||||
|
||||
void
|
||||
tpdu_write_connection_confirm(STREAM* s, uint16 length)
|
||||
{
|
||||
tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Disconnect Request TPDU.
|
||||
* @param s stream
|
||||
|
||||
@@ -43,8 +43,10 @@ enum X224_TPDU_TYPE
|
||||
|
||||
uint8 tpdu_read_header(STREAM* s, uint8* code);
|
||||
void tpdu_write_header(STREAM* s, uint16 length, uint8 code);
|
||||
uint8 tpdu_read_connection_request(STREAM* s);
|
||||
void tpdu_write_connection_request(STREAM* s, uint16 length);
|
||||
uint8 tpdu_read_connection_confirm(STREAM* s);
|
||||
void tpdu_write_connection_confirm(STREAM* s, uint16 length);
|
||||
void tpdu_write_disconnect_request(STREAM* s, uint16 length);
|
||||
uint16 tpdu_read_data(STREAM* s);
|
||||
void tpdu_write_data(STREAM* s);
|
||||
|
||||
@@ -63,6 +63,11 @@ boolean transport_connect(rdpTransport* transport, const char* hostname, uint16
|
||||
return transport->tcp->connect(transport->tcp, hostname, port);
|
||||
}
|
||||
|
||||
void transport_attach(rdpTransport* transport, int sockfd)
|
||||
{
|
||||
transport->tcp->sockfd = sockfd;
|
||||
}
|
||||
|
||||
boolean transport_disconnect(rdpTransport* transport)
|
||||
{
|
||||
return transport->tcp->disconnect(transport->tcp);
|
||||
|
||||
@@ -69,6 +69,7 @@ struct rdp_transport
|
||||
STREAM* transport_recv_stream_init(rdpTransport* transport, int size);
|
||||
STREAM* transport_send_stream_init(rdpTransport* transport, int size);
|
||||
boolean transport_connect(rdpTransport* transport, const char* hostname, uint16 port);
|
||||
void transport_attach(rdpTransport* transport, int sockfd);
|
||||
boolean transport_disconnect(rdpTransport* transport);
|
||||
boolean transport_connect_rdp(rdpTransport* transport);
|
||||
boolean transport_connect_tls(rdpTransport* transport);
|
||||
|
||||
@@ -85,11 +85,11 @@ static void* test_peer_mainloop(void* arg)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Client %s disconnected.\n", client->settings->hostname);
|
||||
|
||||
client->Disconnect(client);
|
||||
freerdp_peer_free(client);
|
||||
|
||||
printf("Client %s disconnected.\n", client->settings->hostname);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user