added command line options to specify preconnection PDU information

This commit is contained in:
lysannkessler 2012-07-25 18:46:43 +02:00
parent 3c6df95978
commit d9c260f221
5 changed files with 140 additions and 30 deletions

View File

@ -296,7 +296,10 @@ struct rdp_settings
ALIGN64 boolean local; /* 68 */
ALIGN64 boolean authentication_only; /* 69 */
ALIGN64 boolean from_stdin; /* 70 */
ALIGN64 uint64 paddingC[80 - 71]; /* 71 */
ALIGN64 boolean send_preconnection_pdu; /* 71 */
ALIGN64 uint32 preconnection_id; /* 72 */
ALIGN64 char* preconnection_blob; /* 73 */
ALIGN64 uint64 paddingC[80 - 74]; /* 74 */
/* User Interface Parameters */
ALIGN64 boolean sw_gdi; /* 80 */

View File

@ -55,25 +55,6 @@
*
*/
// XXX: Send a PCB (preconnection BLOB) as specified in MS-RDPEPS (RDP_PRECONNECTION_PDU_V2)
boolean rdp_send_pcb(rdpNego* nego) {
STREAM* s;
// XXX: this is a fixed RDP_PRECONNECTION_PDU_V2, with Id=0 and a Hyper-V instance id as string
// must be customizable in the final version.
// 49ECFD99-8A50-43DC-B2EF-39965652C371
uint8 buf[] = {0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 52, 0, 57, 0, 69, 0, 67, 0, 70, 0, 68, 0, 57, 0, 57, 0, 45, 0, 56, 0, 65, 0, 53, 0, 48, 0, 45, 0, 52, 0, 51, 0, 68, 0, 67, 0, 45, 0, 66, 0, 50, 0, 69, 0, 70, 0, 45, 0, 51, 0, 57, 0, 57, 0, 54, 0, 53, 0, 54, 0, 53, 0, 50, 0, 67, 0, 51, 0, 55, 0, 49, 0, 0x00, 0x00};
if(!nego_tcp_connect(nego)) return false;
s = transport_send_stream_init(nego->transport, 93);
stream_write(s, buf, 92);
if (transport_write(nego->transport, s) < 0)
return false;
return true;
}
/**
* Establish RDP Connection based on the settings given in the 'rdp' paremeter.
* @msdn{cc240452}
@ -88,6 +69,10 @@ boolean rdp_client_connect(rdpRdp* rdp)
nego_init(rdp->nego);
nego_set_target(rdp->nego, settings->hostname, settings->port);
nego_set_cookie(rdp->nego, settings->username);
nego_set_send_preconnection_pdu(rdp->nego, settings->send_preconnection_pdu);
nego_set_preconnection_id(rdp->nego, settings->preconnection_id);
nego_set_preconnection_blob(rdp->nego, settings->preconnection_blob);
nego_set_negotiation_enabled(rdp->nego, settings->security_layer_negotiation);
nego_enable_rdp(rdp->nego, settings->rdp_security);
@ -97,8 +82,6 @@ boolean rdp_client_connect(rdpRdp* rdp)
nego_enable_tls(rdp->nego, settings->tls_security);
}
rdp_send_pcb(rdp->nego); // XXX: different name?!
if (!nego_connect(rdp->nego))
{
printf("Error: protocol security negotiation failure\n");

View File

@ -81,6 +81,13 @@ boolean nego_connect(rdpNego* nego)
else if (nego->state == NEGO_STATE_RDP)
nego->enabled_protocols[PROTOCOL_RDP] = 1;
}
if(!nego_send_preconnection_pdu(nego))
{
DEBUG_NEGO("Failed to send preconnection information");
nego->state = NEGO_STATE_FINAL;
return false;
}
}
do
@ -143,9 +150,7 @@ boolean nego_security_connect(rdpNego* nego)
boolean nego_tcp_connect(rdpNego* nego)
{
if (!nego->tcp_connected)
{
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
return nego->tcp_connected;
}
@ -160,10 +165,7 @@ boolean nego_transport_connect(rdpNego* nego)
nego_tcp_connect(nego);
if (nego->tcp_connected && !nego->security_layer_negotiation_enabled)
{
nego_security_connect(nego);
return nego->security_connected;
}
return nego_security_connect(nego);
return nego->tcp_connected;
}
@ -184,6 +186,55 @@ int nego_transport_disconnect(rdpNego* nego)
return 1;
}
/**
* Send preconnection information if enabled.
* @param nego
* @return
*/
boolean nego_send_preconnection_pdu(rdpNego* nego)
{
STREAM* s;
uint32 cbSize;
UNICONV* uniconv;
uint16 cchPCB_times2 = 0;
char* wszPCB = NULL;
if(!nego->send_preconnection_pdu)
return true;
DEBUG_NEGO("Sending preconnection PDU");
if(!nego_tcp_connect(nego))
return false;
/* it's easier to always send the version 2 PDU, and it's just 2 bytes overhead */
cbSize = PRECONNECTION_PDU_V2_MIN_SIZE;
if(nego->preconnection_blob) {
uniconv = freerdp_uniconv_new();
wszPCB = freerdp_uniconv_out(uniconv, nego->preconnection_blob, &cchPCB_times2);
freerdp_uniconv_free(uniconv);
cchPCB_times2 += 2; /* zero-termination */
cbSize += cchPCB_times2;
}
s = transport_send_stream_init(nego->transport, cbSize);
stream_write_uint32(s, cbSize); /* cbSize */
stream_write_uint32(s, 0); /* Flags */
stream_write_uint32(s, PRECONNECTION_PDU_V2); /* Version */
stream_write_uint32(s, nego->preconnection_id); /* Id */
stream_write_uint16(s, cchPCB_times2 / 2); /* cchPCB */
if(wszPCB)
{
stream_write(s, wszPCB, cchPCB_times2); /* wszPCB */
xfree(wszPCB);
}
if (transport_write(nego->transport, s) < 0)
return false;
return true;
}
/**
* Attempt negotiating NLA + TLS security.
* @param nego
@ -821,3 +872,36 @@ void nego_set_cookie(rdpNego* nego, char* cookie)
{
nego->cookie = cookie;
}
/**
* Enable / disable preconnection PDU.
* @param nego
* @param send_pcpdu
*/
void nego_set_send_preconnection_pdu(rdpNego* nego, boolean send_pcpdu)
{
nego->send_preconnection_pdu = send_pcpdu;
}
/**
* Set preconnection id.
* @param nego
* @param id
*/
void nego_set_preconnection_id(rdpNego* nego, uint32 id)
{
nego->preconnection_id = id;
}
/**
* Set preconnection blob.
* @param nego
* @param blob
*/
void nego_set_preconnection_blob(rdpNego* nego, char* blob)
{
nego->preconnection_blob = blob;
}

View File

@ -68,28 +68,41 @@ enum RDP_NEG_MSG
#define EXTENDED_CLIENT_DATA_SUPPORTED 0x01
#define PRECONNECTION_PDU_V1_SIZE 16
#define PRECONNECTION_PDU_V2_MIN_SIZE (PRECONNECTION_PDU_V1_SIZE+2)
#define PRECONNECTION_PDU_V1 1
#define PRECONNECTION_PDU_V2 2
struct rdp_nego
{
int port;
uint32 flags;
char* hostname;
char* cookie;
rdpBlob* routing_token;
boolean send_preconnection_pdu;
uint32 preconnection_id;
char* preconnection_blob;
NEGO_STATE state;
boolean tcp_connected;
boolean security_connected;
rdpBlob* routing_token;
uint32 selected_protocol;
uint32 requested_protocols;
boolean security_layer_negotiation_enabled;
uint8 enabled_protocols[3];
rdpTransport* transport;
};
typedef struct rdp_nego rdpNego;
boolean nego_connect(rdpNego* nego);
boolean nego_tcp_connect(rdpNego* nego);
boolean nego_security_connect(rdpNego* nego);
boolean nego_send_preconnection_pdu(rdpNego* nego);
void nego_attempt_nla(rdpNego* nego);
void nego_attempt_tls(rdpNego* nego);
void nego_attempt_rdp(rdpNego* nego);
@ -115,6 +128,9 @@ void nego_enable_nla(rdpNego* nego, boolean enable_nla);
void nego_enable_tls(rdpNego* nego, boolean enable_tls);
void nego_set_routing_token(rdpNego* nego, rdpBlob* routing_token);
void nego_set_cookie(rdpNego* nego, char* cookie);
void nego_set_send_preconnection_pdu(rdpNego* nego, boolean send_pcpdu);
void nego_set_preconnection_id(rdpNego* nego, uint32 id);
void nego_set_preconnection_blob(rdpNego* nego, char* blob);
#ifdef WITH_DEBUG_NEGO
#define DEBUG_NEGO(fmt, ...) DEBUG_CLASS(NEGO, fmt, ## __VA_ARGS__)

View File

@ -133,6 +133,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
" --tsg: Terminal Server Gateway (<username> <password> <hostname>)\n"
" --kbd-list: list all keyboard layout ids used by -k\n"
" --no-salted-checksum: disable salted checksums with Standard RDP encryption\n"
" --pcid: preconnection id\n"
" --pcb: preconnection blob\n"
" --version: print version information\n"
"\n", argv[0]);
return FREERDP_ARGS_PARSE_HELP; /* TODO: What is the correct return? */
@ -703,6 +705,28 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
{
settings->salted_checksum = false;
}
else if (strcmp("--pcid", argv[index]) == 0)
{
index++;
if (index == argc)
{
printf("missing preconnection id value\n");
return -1;
}
settings->send_preconnection_pdu = true;
settings->preconnection_id = atoi(argv[index]);
}
else if (strcmp("--pcb", argv[index]) == 0)
{
index++;
if (index == argc)
{
printf("missing preconnection blob value\n");
return -1;
}
settings->send_preconnection_pdu = true;
settings->preconnection_blob = xstrdup(argv[index]);
}
else if (strcmp("--version", argv[index]) == 0)
{
printf("This is FreeRDP version %s\n", FREERDP_VERSION_FULL);