libfreerdp/peer: initial protocol negotiation.

This commit is contained in:
Vic Lee
2011-08-18 23:15:28 +08:00
parent 9d414132e4
commit 8cced27d17
10 changed files with 248 additions and 7 deletions

View File

@@ -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 */

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -29,7 +29,8 @@ struct rdp_peer
{
freerdp_peer* client;
int sockfd;
rdpRdp* rdp;
int state;
};
#endif /* __PEER */

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}