static int
packet_received(rdpTransport * transport, STREAM * stream, void * extra)
{
+#if 0
uint16 length;
length = tpkt_read_header(stream);
CU_ASSERT(length == 19);
freerdp_hexdump(stream->data, length);
test_finished = 1;
return 0;
+#endif
}
void test_transport(void)
{
+#if 0
rdpTransport * transport;
STREAM * stream;
int r;
CU_ASSERT(r == True);
transport_free(transport);
+#endif
}
settings.c
connection.c
connection.h
+ rdp.c
+ rdp.h
per.c
per.h
tcp.c
{
STREAM* s;
int length;
- s = stream_new(1024);
-
uint8 *bm, *em;
+ s = transport_send_stream_init(connection->transport, 1024);
+
stream_get_mark(s, bm);
stream_seek(s, 15);
- /* security header */
- stream_write_uint16(s, SEC_INFO_PKT); /* flags */
- stream_write_uint16(s, 0); /* flagsHi */
-
+ rdp_write_security_header(s, SEC_INFO_PKT);
connection_write_info_packet(s, connection->settings);
stream_get_mark(s, em);
stream_set_mark(s, em);
- tls_write(connection->transport->tls, s->data, stream_get_length(s));
+ transport_write(connection->transport, s);
}
/**
#ifndef __CONNECTION_H
#define __CONNECTION_H
+#include "rdp.h"
#include "tpkt.h"
#include "tpdu.h"
#include "nego.h"
#define PACKET_COMPR_TYPE_RDP6 0x00000300
#define PACKET_COMPR_TYPE_RDP61 0x00000400
-/* Security Header Flags */
-#define SEC_EXCHANGE_PKT 0x0001
-#define SEC_ENCRYPT 0x0008
-#define SEC_RESET_SEQNO 0x0010
-#define SEC_IGNORE_SEQNO 0x0020
-#define SEC_INFO_PKT 0x0040
-#define SEC_LICENSE_PKT 0x0080
-#define SEC_LICENSE_ENCRYPT_CS 0x0200
-#define SEC_LICENSE_ENCRYPT_SC 0x0200
-#define SEC_REDIRECTION_PKT 0x0400
-#define SEC_SECURE_CHECKSUM 0x0800
-#define SEC_FLAGSHI_VALID 0x8000
-
struct rdp_connection
{
struct rdp_mcs* mcs;
void credssp_send(rdpCredssp* credssp, BLOB* negoToken, BLOB* pubKeyAuth, BLOB* authInfo)
{
+ STREAM* s;
+ size_t size;
TSRequest_t *ts_request;
OCTET_STRING_t *nego_token;
asn_enc_rval_t enc_rval;
- char* buffer;
- size_t size;
-
ts_request = calloc(1, sizeof(TSRequest_t));
ts_request->version = 2;
if (enc_rval.encoded != -1)
{
size = enc_rval.encoded;
- buffer = xmalloc(size);
+ s = transport_send_stream_init(credssp->transport, size);
- enc_rval = der_encode_to_buffer(&asn_DEF_TSRequest, ts_request, buffer, size);
+ enc_rval = der_encode_to_buffer(&asn_DEF_TSRequest, ts_request, s->data, size);
if (enc_rval.encoded != -1)
{
- tls_write(credssp->transport->tls, buffer, size);
+ s->p = s->data + size;
+ transport_write(credssp->transport, s);
}
asn_DEF_TSRequest.free_struct(&asn_DEF_TSRequest, ts_request, 0);
- xfree(buffer);
}
}
int credssp_recv(rdpCredssp* credssp, BLOB* negoToken, BLOB* pubKeyAuth, BLOB* authInfo)
{
- int bytes_read;
- int size = 2048;
- char *recv_buffer;
+ STREAM* s;
+ int status;
asn_dec_rval_t dec_rval;
TSRequest_t *ts_request = 0;
- recv_buffer = xmalloc(size);
- bytes_read = tls_read(credssp->transport->tls, recv_buffer, size);
+ s = transport_recv_stream_init(credssp->transport, 2048);
+ status = transport_read(credssp->transport, s);
- if (bytes_read < 0)
+ if (status < 0)
return -1;
- dec_rval = ber_decode(0, &asn_DEF_TSRequest, (void **)&ts_request, recv_buffer, bytes_read);
+ dec_rval = ber_decode(0, &asn_DEF_TSRequest, (void **)&ts_request, s->data, status);
if(dec_rval.code == RC_OK)
{
asn_DEF_TSRequest.free_struct(&asn_DEF_TSRequest, ts_request, 0);
}
- xfree(recv_buffer);
return 0;
}
gcc_write_conference_create_request(gcc_CCrq, client_data);
length = stream_get_length(gcc_CCrq) + 7;
- s = stream_new(512);
+ s = transport_send_stream_init(mcs->transport, 1024);
stream_get_mark(s, bm);
stream_seek(s, 7);
tpdu_write_data(s);
stream_set_mark(s, em);
- tls_write(mcs->transport->tls, s->data, stream_get_length(s));
+ transport_write(mcs->transport, s);
}
void mcs_recv_connect_response(rdpMcs* mcs)
uint8 result;
uint32 calledConnectId;
- s = stream_new(1024);
- tls_read(mcs->transport->tls, s->data, s->size);
+ s = transport_recv_stream_init(mcs->transport, 1024);
+ transport_read(mcs->transport, s);
tpkt_read_header(s);
tpdu_read_data(s);
{
STREAM* s;
int length = 12;
- s = stream_new(length);
+ s = transport_send_stream_init(mcs->transport, length);
tpkt_write_header(s, length);
tpdu_write_data(s);
per_write_integer(s, 0); /* subHeight (INTEGER) */
per_write_integer(s, 0); /* subInterval (INTEGER) */
- tls_write(mcs->transport->tls, s->data, stream_get_length(s));
+ transport_write(mcs->transport, s);
}
void mcs_send_attach_user_request(rdpMcs* mcs)
{
STREAM* s;
int length = 8;
- s = stream_new(length);
+ s = transport_send_stream_init(mcs->transport, length);
tpkt_write_header(s, length);
tpdu_write_data(s);
/* DomainMCSPDU, AttachUserRequest */
per_write_choice(s, DomainMCSPDU_AttachUserRequest << 2);
- tls_write(mcs->transport->tls, s->data, stream_get_length(s));
+ transport_write(mcs->transport, s);
}
void mcs_recv_attach_user_confirm(rdpMcs* mcs)
uint8 result;
uint8 choice;
- s = stream_new(32);
- tls_read(mcs->transport->tls, s->data, s->size);
+ s = transport_recv_stream_init(mcs->transport, 32);
+ transport_read(mcs->transport, s);
tpkt_read_header(s);
tpdu_read_data(s);
{
STREAM* s;
int length = 12;
- s = stream_new(length);
+ s = transport_send_stream_init(mcs->transport, 12);
tpkt_write_header(s, length);
tpdu_write_data(s);
per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID);
per_write_integer16(s, channel_id + MCS_BASE_CHANNEL_ID, 0);
- tls_write(mcs->transport->tls, s->data, stream_get_length(s));
+ transport_write(mcs->transport, s);
}
void mcs_recv_channel_join_confirm(rdpMcs* mcs)
uint16 requested;
uint16 channelId;
- s = stream_new(32);
- tls_read(mcs->transport->tls, s->data, s->size);
+ s = transport_recv_stream_init(mcs->transport, 32);
+ transport_read(mcs->transport, s);
tpkt_read_header(s);
tpdu_read_data(s);
uint8 result;
uint8 choice;
- s = stream_new(32);
- tls_read(mcs->transport->tls, s->data, s->size);
+ s = transport_recv_stream_init(mcs->transport, 1024);
+ transport_read(mcs->transport, s);
}
/**
void nego_recv_response(rdpNego* nego)
{
- while (nego->state != NEGO_STATE_FINAL && nego->state != NEGO_STATE_FAIL)
- {
- transport_check_fds(nego->transport);
- }
+ STREAM* s = transport_recv_stream_init(nego->transport, 1024);
+ transport_read(nego->transport, s);
+ nego_recv(nego->transport, s, nego->transport->recv_extra);
}
/**
tpdu_write_connection_request(s, length - 5);
stream_set_mark(s, em);
- transport_send(nego->transport, s);
+ transport_write(nego->transport, s);
}
/**
--- /dev/null
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * RDP Core
+ *
+ * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rdp.h"
+
+void rdp_write_security_header(STREAM* s, uint16 flags)
+{
+ /* Basic Security Header */
+ stream_write_uint16(s, flags); /* flags */
+ stream_write_uint16(s, 0); /* flagsHi (unused) */
+}
--- /dev/null
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * RDP Core
+ *
+ * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RDP_H
+#define __RDP_H
+
+#include <freerdp/freerdp.h>
+#include <freerdp/utils/stream.h>
+
+/* Security Header Flags */
+#define SEC_EXCHANGE_PKT 0x0001
+#define SEC_ENCRYPT 0x0008
+#define SEC_RESET_SEQNO 0x0010
+#define SEC_IGNORE_SEQNO 0x0020
+#define SEC_INFO_PKT 0x0040
+#define SEC_LICENSE_PKT 0x0080
+#define SEC_LICENSE_ENCRYPT_CS 0x0200
+#define SEC_LICENSE_ENCRYPT_SC 0x0200
+#define SEC_REDIRECTION_PKT 0x0400
+#define SEC_SECURE_CHECKSUM 0x0800
+#define SEC_FLAGSHI_VALID 0x8000
+
+void rdp_write_security_header(STREAM* s, uint16 flags);
+
+#endif /* __RDP_H */
tcp->settings->ip_address = tcp->ip_address;
}
-boolean tcp_connect(rdpTcp* tcp, const char* hostname, int port)
+boolean tcp_connect(rdpTcp* tcp, const uint8* hostname, uint16 port)
{
int status;
int sockfd = -1;
return True;
}
+int tcp_read(rdpTcp* tcp, uint8* data, int length)
+{
+ int status;
+
+ status = recv(tcp->sockfd, data, length, 0);
+
+ if (status < 0)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return 0;
+
+ perror("recv");
+ return -1;
+ }
+
+ return status;
+}
+
+int tcp_write(rdpTcp* tcp, uint8* data, int length)
+{
+ int status;
+ int sent = 0;
+
+ while (sent < length)
+ {
+ status = send(tcp->sockfd, data, (length - sent), MSG_NOSIGNAL);
+
+ if (status < 0)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ continue;
+
+ perror("send");
+ return -1;
+ }
+ else
+ {
+ sent += status;
+ data += status;
+ }
+ }
+
+ return sent;
+}
+
boolean tcp_disconnect(rdpTcp * tcp)
{
if (tcp->sockfd != -1)
#include <freerdp/utils/stream.h>
typedef struct rdp_tcp rdpTcp;
-typedef boolean (*TcpConnect) (rdpTcp* tcp, const char* hostname, int port);
+typedef boolean (*TcpConnect) (rdpTcp* tcp, const uint8* hostname, uint16 port);
typedef boolean (*TcpDisconnect) (rdpTcp* tcp);
typedef boolean (*TcpSetBlockingMode) (rdpTcp* tcp, boolean blocking);
TcpSetBlockingMode set_blocking_mode;
};
-boolean tcp_connect(rdpTcp* tcp, const char* hostname, int port);
+boolean tcp_connect(rdpTcp* tcp, const uint8* hostname, uint16 port);
boolean tcp_disconnect(rdpTcp* tcp);
+int tcp_read(rdpTcp* tcp, uint8* data, int length);
+int tcp_write(rdpTcp* tcp, uint8* data, int length);
boolean tcp_set_blocking_mode(rdpTcp* tcp, boolean blocking);
rdpTcp* tcp_new(rdpSettings* settings);
return True;
}
-int tls_read(rdpTls* tls, char* data, int length)
+int tls_read(rdpTls* tls, uint8* data, int length)
{
int status;
return 0;
}
-int tls_write(rdpTls* tls, char* data, int length)
+int tls_write(rdpTls* tls, uint8* data, int length)
{
- int bytes = 0;
- int write_status;
+ int status;
+ int sent = 0;
- while (bytes < length)
+ while (sent < length)
{
- write_status = SSL_write(tls->ssl, data, length);
+ status = SSL_write(tls->ssl, data, length);
- switch (SSL_get_error(tls->ssl, write_status))
+ switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_NONE:
- bytes += write_status;
+ sent += status;
+ data += status;
break;
case SSL_ERROR_WANT_WRITE:
break;
default:
- tls_print_error("SSL_write", tls->ssl, write_status);
+ tls_print_error("SSL_write", tls->ssl, status);
return -1;
break;
}
}
- return bytes;
+
+ return sent;
}
boolean tls_print_error(char *func, SSL *connection, int value)
boolean tls_connect(rdpTls* tls);
boolean tls_disconnect(rdpTls* tls);
-int tls_read(rdpTls* tls, char* data, int length);
-int tls_write(rdpTls* tls, char* data, int length);
+int tls_read(rdpTls* tls, uint8* data, int length);
+int tls_write(rdpTls* tls, uint8* data, int length);
CryptoCert tls_get_certificate(rdpTls* tls);
boolean tls_print_error(char* func, SSL* connection, int value);
#define BUFFER_SIZE 16384
-boolean transport_connect(rdpTransport* transport, const char* server, int port)
+STREAM* transport_recv_stream_init(rdpTransport* transport, int size)
{
- return transport->tcp->connect(transport->tcp, server, port);
+ STREAM* s = transport->recv_stream;
+ stream_check_size(s, size);
+ stream_set_pos(s, 0);
+ return s;
+}
+
+STREAM* transport_send_stream_init(rdpTransport* transport, int size)
+{
+ STREAM* s = transport->send_stream;
+ stream_check_size(s, size);
+ stream_set_pos(s, 0);
+ return s;
+}
+
+boolean transport_connect(rdpTransport* transport, const uint8* hostname, uint16 port)
+{
+ return transport->tcp->connect(transport->tcp, hostname, port);
}
boolean transport_disconnect(rdpTransport* transport)
if (transport->tls == NULL)
transport->tls = tls_new();
+ transport->layer = TRANSPORT_LAYER_TLS;
transport->state = TRANSPORT_STATE_TLS;
-
transport->tls->sockfd = transport->tcp->sockfd;
if (tls_connect(transport->tls) != True)
if (transport->tls == NULL)
transport->tls = tls_new();
+ transport->layer = TRANSPORT_LAYER_TLS;
transport->state = TRANSPORT_STATE_NLA;
-
transport->tls->sockfd = transport->tcp->sockfd;
if (tls_connect(transport->tls) != True)
return True;
}
-static int transport_read(rdpTransport* transport);
-
-static int transport_delay(rdpTransport* transport)
+int transport_delay(rdpTransport* transport, STREAM* s)
{
- transport_read(transport);
+ transport_read(transport, s);
nanosleep(&transport->ts, NULL);
return 0;
}
-static int transport_send_tls(rdpTransport* transport, STREAM * stream)
-{
- return 0;
-}
-
-static int transport_send_tcp(rdpTransport* transport, STREAM * stream)
-{
- int bytes;
- uint8 * head;
- uint8 * tail;
-
- head = stream_get_head(stream);
- tail = stream_get_tail(stream);
-
- while (head < tail)
- {
- bytes = send(transport->tcp->sockfd, head, tail - head, MSG_NOSIGNAL);
-
- if (bytes < 0)
- {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- {
- if (transport_delay(transport) != 0)
- return -1;
-
- continue;
- }
-
- perror("send");
- return -1;
- }
- head += bytes;
- }
-
- return 0;
-}
-
-int transport_send(rdpTransport* transport, STREAM * stream)
+int transport_read(rdpTransport* transport, STREAM* s)
{
- int r;
-
- if (transport->state == TRANSPORT_STATE_TLS)
- r = transport_send_tls(transport, stream);
- else
- r = transport_send_tcp(transport, stream);
+ int status = -1;
- if (r == 0)
- r = transport_check_fds(transport);
+ if (transport->layer == TRANSPORT_LAYER_TLS)
+ status = tls_read(transport->tls, s->data, s->size);
+ else if (transport->layer == TRANSPORT_LAYER_TCP)
+ status = tcp_read(transport->tcp, s->data, s->size);
- return r;
+ return status;
}
-static int transport_read_tls(rdpTransport* transport)
+int transport_write(rdpTransport* transport, STREAM* s)
{
- return 0;
-}
+ int status = -1;
-static int transport_read_tcp(rdpTransport* transport)
-{
- int bytes;
+ if (transport->layer == TRANSPORT_LAYER_TLS)
+ status = tls_write(transport->tls, s->data, stream_get_length(s));
+ else if (transport->layer == TRANSPORT_LAYER_TCP)
+ status = tcp_write(transport->tcp, s->data, stream_get_length(s));
- stream_check_size(transport->recv_buffer, BUFFER_SIZE);
-
- bytes = recv(transport->tcp->sockfd, transport->recv_buffer->p, BUFFER_SIZE, 0);
-
- if (bytes == -1)
- {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- return 0;
-
- perror("recv");
- return -1;
- }
-
- stream_seek(transport->recv_buffer, bytes);
-
- return bytes;
-}
-
-static int transport_read(rdpTransport* transport)
-{
- if (transport->state == TRANSPORT_STATE_TLS)
- return transport_read_tls(transport);
- else
- return transport_read_tcp(transport);
+ return status;
}
int transport_check_fds(rdpTransport* transport)
uint16 length;
STREAM* received;
- bytes = transport_read(transport);
+ bytes = transport_read(transport, transport->recv_buffer);
if (bytes <= 0)
return bytes;
void transport_init(rdpTransport* transport)
{
+ transport->layer = TRANSPORT_LAYER_TCP;
transport->state = TRANSPORT_STATE_NEGO;
}
/* receive buffer for non-blocking read. */
transport->recv_buffer = stream_new(BUFFER_SIZE);
+
+ /* buffers for blocking read/write */
+ transport->recv_stream = stream_new(BUFFER_SIZE);
+ transport->send_stream = stream_new(BUFFER_SIZE);
}
return transport;
if (transport != NULL)
{
stream_free(transport->recv_buffer);
+ stream_free(transport->recv_stream);
+ stream_free(transport->send_stream);
tcp_free(transport->tcp);
xfree(transport);
}
#ifndef __TRANSPORT_H
#define __TRANSPORT_H
+typedef enum
+{
+ TRANSPORT_LAYER_TCP,
+ TRANSPORT_LAYER_TLS
+} TRANSPORT_LAYER;
+
+typedef enum
+{
+ TRANSPORT_STATE_INITIAL,
+ TRANSPORT_STATE_NEGO,
+ TRANSPORT_STATE_RDP,
+ TRANSPORT_STATE_TLS,
+ TRANSPORT_STATE_NLA,
+ TRANSPORT_STATE_FINAL
+} TRANSPORT_STATE;
+
typedef struct rdp_transport rdpTransport;
#include "tcp.h"
#include <freerdp/settings.h>
#include <freerdp/utils/stream.h>
-enum _TRANSPORT_STATE
-{
- TRANSPORT_STATE_INITIAL,
- TRANSPORT_STATE_NEGO,
- TRANSPORT_STATE_RDP,
- TRANSPORT_STATE_TLS,
- TRANSPORT_STATE_NLA,
- TRANSPORT_STATE_FINAL
-};
-typedef enum _TRANSPORT_STATE TRANSPORT_STATE;
-
typedef int (*TransportRecv) (rdpTransport* transport, STREAM* stream, void* extra);
struct rdp_transport
{
+ STREAM* recv_stream;
+ STREAM* send_stream;
+ TRANSPORT_LAYER layer;
TRANSPORT_STATE state;
struct rdp_tcp* tcp;
struct rdp_tls* tls;
TransportRecv recv_callback;
};
-rdpTransport* transport_new(rdpSettings* settings);
-void transport_free(rdpTransport* transport);
-boolean transport_connect(rdpTransport* transport, const char* server, int port);
+STREAM* transport_recv_stream_init(rdpTransport* transport, int size);
+STREAM* transport_send_stream_init(rdpTransport* transport, int size);
+boolean transport_connect(rdpTransport* transport, const uint8* hostname, uint16 port);
boolean transport_disconnect(rdpTransport* transport);
boolean transport_connect_rdp(rdpTransport* transport);
boolean transport_connect_tls(rdpTransport* transport);
boolean transport_connect_nla(rdpTransport* transport);
-int transport_send(rdpTransport* transport, STREAM* stream);
+int transport_read(rdpTransport* transport, STREAM* s);
+int transport_write(rdpTransport* transport, STREAM* s);
int transport_check_fds(rdpTransport* transport);
+rdpTransport* transport_new(rdpSettings* settings);
+void transport_free(rdpTransport* transport);
#endif