diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 421306c50..539f5ffa2 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -329,13 +329,14 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) rdpBrush* brush; uint32 foreColor; uint32 backColor; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; brush = &patblt->brush; xf_set_rop3(xfi, gdi_rop3_code(patblt->bRop)); - foreColor = freerdp_color_convert_rgb(patblt->foreColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); - backColor = freerdp_color_convert_rgb(patblt->backColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + foreColor = freerdp_color_convert_rgb(patblt->foreColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); + backColor = freerdp_color_convert_rgb(patblt->backColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); if (brush->style == GDI_BS_SOLID) { @@ -436,9 +437,10 @@ void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) { uint32 color; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; - color = freerdp_color_convert_var(opaque_rect->color, xfi->srcBpp, xfi->bpp, xfi->clrconv); + color = freerdp_color_convert_var(opaque_rect->color, context_->settings->color_depth, xfi->bpp, xfi->clrconv); XSetFunction(xfi->display, xfi->gc, GXcopy); XSetFillStyle(xfi->display, xfi->gc, FillSolid); @@ -466,9 +468,10 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult int i; uint32 color; DELTA_RECT* rectangle; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; - color = freerdp_color_convert_var(multi_opaque_rect->color, xfi->srcBpp, xfi->bpp, xfi->clrconv); + color = freerdp_color_convert_var(multi_opaque_rect->color, context_->settings->color_depth, xfi->bpp, xfi->clrconv); XSetFunction(xfi->display, xfi->gc, GXcopy); XSetFillStyle(xfi->display, xfi->gc, FillSolid); @@ -503,10 +506,11 @@ void xf_gdi_draw_nine_grid(rdpContext* context, DRAW_NINE_GRID_ORDER* draw_nine_ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to) { uint32 color; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; xf_set_rop2(xfi, line_to->bRop2); - color = freerdp_color_convert_rgb(line_to->penColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + color = freerdp_color_convert_rgb(line_to->penColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); XSetFillStyle(xfi->display, xfi->gc, FillSolid); XSetForeground(xfi->display, xfi->gc, color); @@ -550,10 +554,11 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) uint32 color; XPoint* points; int width, height; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; xf_set_rop2(xfi, polyline->bRop2); - color = freerdp_color_convert_var(polyline->penColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + color = freerdp_color_convert_var(polyline->penColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); XSetFillStyle(xfi->display, xfi->gc, FillSolid); XSetForeground(xfi->display, xfi->gc, color); @@ -636,13 +641,14 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) uint32 foreColor; uint32 backColor; Pixmap pattern = 0; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; brush = &mem3blt->brush; bitmap = (xfBitmap*) mem3blt->bitmap; xf_set_rop3(xfi, gdi_rop3_code(mem3blt->bRop)); - foreColor = freerdp_color_convert_rgb(mem3blt->foreColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); - backColor = freerdp_color_convert_rgb(mem3blt->backColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + foreColor = freerdp_color_convert_rgb(mem3blt->foreColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); + backColor = freerdp_color_convert_rgb(mem3blt->backColor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); if (brush->style == GDI_BS_PATTERN) { @@ -711,7 +717,7 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) xfInfo* xfi = ((xfContext*) context)->xfi; xf_set_rop2(xfi, polygon_sc->bRop2); - brush_color = freerdp_color_convert_var(polygon_sc->brushColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + brush_color = freerdp_color_convert_var(polygon_sc->brushColor, ((xfContext*)context)->settings->color_depth, xfi->bpp, xfi->clrconv); npoints = polygon_sc->numPoints + 1; points = xmalloc(sizeof(XPoint) * npoints); @@ -768,8 +774,8 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) brush = &(polygon_cb->brush); xf_set_rop2(xfi, polygon_cb->bRop2); - foreColor = freerdp_color_convert_rgb(polygon_cb->foreColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); - backColor = freerdp_color_convert_rgb(polygon_cb->backColor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + foreColor = freerdp_color_convert_rgb(polygon_cb->foreColor, ((xfContext*)context)->settings->color_depth, xfi->bpp, xfi->clrconv); + backColor = freerdp_color_convert_rgb(polygon_cb->backColor, ((xfContext*)context)->settings->color_depth, xfi->bpp, xfi->clrconv); npoints = polygon_cb->numPoints + 1; points = xmalloc(sizeof(XPoint) * npoints); diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index b25dc99d1..cf16820ac 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -35,7 +35,8 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) uint8* data; Pixmap pixmap; XImage* image; - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; XSetFunction(xfi->display, xfi->gc, GXcopy); pixmap = XCreatePixmap(xfi->display, xfi->drawable, bitmap->width, bitmap->height, xfi->depth); @@ -43,7 +44,7 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) if (bitmap->data != NULL) { data = freerdp_image_convert(bitmap->data, NULL, - bitmap->width, bitmap->height, xfi->srcBpp, xfi->bpp, xfi->clrconv); + bitmap->width, bitmap->height, context_->settings->color_depth, xfi->bpp, xfi->clrconv); if (bitmap->ephemeral != true) { @@ -60,7 +61,7 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { if (data != bitmap->data) xfree(bitmap->data); - + bitmap->data = data; } } @@ -270,15 +271,16 @@ void xf_Glyph_Draw(rdpContext* context, rdpGlyph* glyph, int x, int y) void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height, uint32 bgcolor, uint32 fgcolor) { - xfInfo* xfi = ((xfContext*) context)->xfi; + xfContext* context_ = (xfContext*) context; + xfInfo* xfi = context_->xfi; bgcolor = (xfi->clrconv->invert)? - freerdp_color_convert_var_bgr(bgcolor, xfi->srcBpp, xfi->bpp, xfi->clrconv): - freerdp_color_convert_var_rgb(bgcolor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + freerdp_color_convert_var_bgr(bgcolor, context_->settings->color_depth, xfi->bpp, xfi->clrconv): + freerdp_color_convert_var_rgb(bgcolor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); fgcolor = (xfi->clrconv->invert)? - freerdp_color_convert_var_bgr(fgcolor, xfi->srcBpp, xfi->bpp, xfi->clrconv): - freerdp_color_convert_var_rgb(fgcolor, xfi->srcBpp, xfi->bpp, xfi->clrconv); + freerdp_color_convert_var_bgr(fgcolor, context_->settings->color_depth, xfi->bpp, xfi->clrconv): + freerdp_color_convert_var_rgb(fgcolor, context_->settings->color_depth, xfi->bpp, xfi->clrconv); XSetFunction(xfi->display, xfi->gc, GXcopy); XSetFillStyle(xfi->display, xfi->gc, FillSolid); diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 7d0a24be8..362037ff0 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -269,7 +269,8 @@ struct rdp_settings ALIGN64 uint32 encryption_level; /* 28 */ ALIGN64 boolean authentication; /* 29 */ ALIGN64 uint32 negotiationFlags; /* 30 */ - ALIGN64 uint64 paddingB[48 - 31]; /* 31 */ + ALIGN64 boolean security_layer_negotiation; /* 31 */ + ALIGN64 uint64 paddingB[48 - 32]; /* 32 */ /* Connection Settings */ ALIGN64 uint32 port; /* 48 */ @@ -295,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 */ diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index f82bb878e..b408992a0 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -21,6 +21,7 @@ #include "input.h" #include "connection.h" +#include "transport.h" #include @@ -63,13 +64,16 @@ boolean rdp_client_connect(rdpRdp* rdp) { - boolean status; - uint32 selectedProtocol; rdpSettings* settings = rdp->settings; 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); if (!settings->ts_gateway) @@ -78,36 +82,23 @@ boolean rdp_client_connect(rdpRdp* rdp) nego_enable_tls(rdp->nego, settings->tls_security); } - if (nego_connect(rdp->nego) != true) + if (!nego_connect(rdp->nego)) { - printf("Error: protocol security negotiation failure\n"); + printf("Error: protocol security negotiation or connection failure\n"); return false; } - selectedProtocol = rdp->nego->selected_protocol; - - if ((selectedProtocol & PROTOCOL_TLS) || (selectedProtocol == PROTOCOL_RDP)) + if ((rdp->nego->selected_protocol & PROTOCOL_TLS) || (rdp->nego->selected_protocol == PROTOCOL_RDP)) { if ((settings->username != NULL) && ((settings->password != NULL) || (settings->password_cookie != NULL && settings->password_cookie->length > 0))) settings->autologon = true; } - status = false; - if (selectedProtocol & PROTOCOL_NLA) - status = transport_connect_nla(rdp->transport); - else if (selectedProtocol & PROTOCOL_TLS) - status = transport_connect_tls(rdp->transport); - else if (selectedProtocol == PROTOCOL_RDP) /* 0 */ - status = transport_connect_rdp(rdp->transport); - - if (status != true) - return false; - rdp_set_blocking_mode(rdp, false); rdp->state = CONNECTION_STATE_NEGO; rdp->finalize_sc_pdus = 0; - if (mcs_send_connect_initial(rdp->mcs) != true) + if (!mcs_send_connect_initial(rdp->mcs)) { if (!connectErrorCode) { diff --git a/libfreerdp-core/connection.h b/libfreerdp-core/connection.h index eb5c0460f..8d05bedb9 100644 --- a/libfreerdp-core/connection.h +++ b/libfreerdp-core/connection.h @@ -25,7 +25,6 @@ #include "tpdu.h" #include "nego.h" #include "mcs.h" -#include "transport.h" #include "activation.h" #include diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index a54330fcf..c77789894 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -42,6 +42,24 @@ #define FASTPATH_MAX_PACKET_SIZE 0x3FFF +#ifdef WITH_DEBUG_RDP +static const char* const FASTPATH_UPDATETYPE_STRINGS[] = +{ + "Orders", /* 0x0 */ + "Bitmap", /* 0x1 */ + "Palette", /* 0x2 */ + "Synchronize", /* 0x3 */ + "Surface Commands", /* 0x4 */ + "System Pointer Hidden", /* 0x5 */ + "System Pointer Default", /* 0x6 */ + "???", /* 0x7 */ + "Pointer Position", /* 0x8 */ + "Color Pointer", /* 0x9 */ + "Cached Pointer", /* 0xA */ + "New Pointer", /* 0xB */ +}; +#endif + /* * The fastpath header may be two or three bytes long. * This function assumes that at least two bytes are available in the stream @@ -170,6 +188,11 @@ static boolean fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uin rdpContext* context = fastpath->rdp->update->context; rdpPointerUpdate* pointer = update->pointer; +#ifdef WITH_DEBUG_RDP + DEBUG_RDP("recv Fast-Path %s Update (0x%X), length:%d", + updateCode < ARRAY_SIZE(FASTPATH_UPDATETYPE_STRINGS) ? FASTPATH_UPDATETYPE_STRINGS[updateCode] : "???", updateCode, size); +#endif + switch (updateCode) { case FASTPATH_UPDATETYPE_ORDERS: diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c index f92d2edfc..0558fca6a 100644 --- a/libfreerdp-core/nego.c +++ b/libfreerdp-core/nego.c @@ -27,6 +27,8 @@ #include "nego.h" +#include "transport.h" + static const char* const NEGO_STATE_STRINGS[] = { "NEGO_STATE_INITIAL", @@ -44,6 +46,8 @@ static const char PROTOCOL_SECURITY_STRINGS[3][4] = "NLA" }; +boolean nego_security_connect(rdpNego* nego); + /** * Negotiate protocol security and connect. * @param nego @@ -61,7 +65,31 @@ boolean nego_connect(rdpNego* nego) else if (nego->enabled_protocols[PROTOCOL_RDP] > 0) nego->state = NEGO_STATE_RDP; else + { + DEBUG_NEGO("No security protocol is enabled"); nego->state = NEGO_STATE_FAIL; + } + + if (!nego->security_layer_negotiation_enabled) + { + DEBUG_NEGO("Security Layer Negotiation is disabled"); + nego->enabled_protocols[PROTOCOL_NLA] = 0; + nego->enabled_protocols[PROTOCOL_TLS] = 0; + nego->enabled_protocols[PROTOCOL_RDP] = 0; + if(nego->state == NEGO_STATE_NLA) + nego->enabled_protocols[PROTOCOL_NLA] = 1; + else if (nego->state == NEGO_STATE_TLS) + nego->enabled_protocols[PROTOCOL_TLS] = 1; + 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 @@ -93,9 +121,35 @@ boolean nego_connect(rdpNego* nego) nego->transport->settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } + /* finally connect security layer (if not already done) */ + if(!nego_security_connect(nego)) + { + DEBUG_NEGO("Failed to connect with %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]); + return false; + } + return true; } +/* connect to selected security layer */ +boolean nego_security_connect(rdpNego* nego) +{ + if(!nego->tcp_connected) + { + nego->security_connected = false; + } + else if (!nego->security_connected) + { + if (nego->enabled_protocols[PROTOCOL_NLA] > 0) + nego->security_connected = transport_connect_nla(nego->transport); + else if (nego->enabled_protocols[PROTOCOL_TLS] > 0) + nego->security_connected = transport_connect_tls(nego->transport); + else if (nego->enabled_protocols[PROTOCOL_RDP] > 0) + nego->security_connected = transport_connect_rdp(nego->transport); + } + return nego->security_connected; +} + /** * Connect TCP layer. * @param nego @@ -104,21 +158,25 @@ boolean nego_connect(rdpNego* nego) boolean nego_tcp_connect(rdpNego* nego) { - if (nego->tcp_connected == 0) - { - if (transport_connect(nego->transport, nego->hostname, nego->port) == false) - { - nego->tcp_connected = 0; - return false; - } - else - { - nego->tcp_connected = 1; - return true; - } - } + if (!nego->tcp_connected) + nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port); + return nego->tcp_connected; +} - return true; +/** + * Connect TCP layer. For direct approach, connect security layer as well. + * @param nego + * @return + */ + +boolean nego_transport_connect(rdpNego* nego) +{ + nego_tcp_connect(nego); + + if (nego->tcp_connected && !nego->security_layer_negotiation_enabled) + return nego_security_connect(nego); + + return nego->tcp_connected; } /** @@ -127,15 +185,65 @@ boolean nego_tcp_connect(rdpNego* nego) * @return */ -int nego_tcp_disconnect(rdpNego* nego) +int nego_transport_disconnect(rdpNego* nego) { if (nego->tcp_connected) transport_disconnect(nego->transport); nego->tcp_connected = 0; + nego->security_connected = 0; 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 @@ -147,7 +255,7 @@ void nego_attempt_nla(rdpNego* nego) DEBUG_NEGO("Attempting NLA security"); - if (!nego_tcp_connect(nego)) + if (!nego_transport_connect(nego)) { nego->state = NEGO_STATE_FAIL; return; @@ -168,7 +276,7 @@ void nego_attempt_nla(rdpNego* nego) DEBUG_NEGO("state: %s", NEGO_STATE_STRINGS[nego->state]); if (nego->state != NEGO_STATE_FINAL) { - nego_tcp_disconnect(nego); + nego_transport_disconnect(nego); if (nego->enabled_protocols[PROTOCOL_TLS] > 0) nego->state = NEGO_STATE_TLS; @@ -190,7 +298,7 @@ void nego_attempt_tls(rdpNego* nego) DEBUG_NEGO("Attempting TLS security"); - if (!nego_tcp_connect(nego)) + if (!nego_transport_connect(nego)) { nego->state = NEGO_STATE_FAIL; return; @@ -210,7 +318,7 @@ void nego_attempt_tls(rdpNego* nego) if (nego->state != NEGO_STATE_FINAL) { - nego_tcp_disconnect(nego); + nego_transport_disconnect(nego); if (nego->enabled_protocols[PROTOCOL_RDP] > 0) nego->state = NEGO_STATE_RDP; @@ -230,7 +338,7 @@ void nego_attempt_rdp(rdpNego* nego) DEBUG_NEGO("Attempting RDP security"); - if (!nego_tcp_connect(nego)) + if (!nego_transport_connect(nego)) { nego->state = NEGO_STATE_FAIL; return; @@ -261,7 +369,7 @@ boolean nego_recv_response(rdpNego* nego) if (transport_read(nego->transport, s) < 0) return false; - return nego_recv(nego->transport, s, nego->transport->recv_extra); + return nego_recv(nego->transport, s, nego); } /** @@ -704,6 +812,18 @@ void nego_set_target(rdpNego* nego, char* hostname, int port) nego->port = port; } +/** + * Enable security layer negotiation. + * @param nego pointer to the negotiation structure + * @param enable_rdp whether to enable security layer negotiation (true for enabled, false for disabled) + */ + +void nego_set_negotiation_enabled(rdpNego* nego, boolean security_layer_negotiation_enabled) +{ + DEBUG_NEGO("Enabling security layer negotiation: %s", security_layer_negotiation_enabled ? "true" : "false"); + nego->security_layer_negotiation_enabled = security_layer_negotiation_enabled; +} + /** * Enable RDP security protocol. * @param nego pointer to the negotiation structure @@ -761,3 +881,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; +} diff --git a/libfreerdp-core/nego.h b/libfreerdp-core/nego.h index 800b3b48c..cf30c94e9 100644 --- a/libfreerdp-core/nego.h +++ b/libfreerdp-core/nego.h @@ -68,24 +68,40 @@ 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; - NEGO_STATE state; - int tcp_connected; rdpBlob* routing_token; + boolean send_preconnection_pdu; + uint32 preconnection_id; + char* preconnection_blob; + + NEGO_STATE state; + boolean tcp_connected; + boolean security_connected; + 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_send_preconnection_pdu(rdpNego* nego); + void nego_attempt_nla(rdpNego* nego); void nego_attempt_tls(rdpNego* nego); void nego_attempt_rdp(rdpNego* nego); @@ -105,11 +121,15 @@ rdpNego* nego_new(struct rdp_transport * transport); void nego_free(rdpNego* nego); void nego_init(rdpNego* nego); void nego_set_target(rdpNego* nego, char* hostname, int port); +void nego_set_negotiation_enabled(rdpNego* nego, boolean security_layer_negotiation_enabled); void nego_enable_rdp(rdpNego* nego, boolean enable_rdp); 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__) diff --git a/libfreerdp-core/settings.c b/libfreerdp-core/settings.c index 4540ed91c..277ea5e19 100644 --- a/libfreerdp-core/settings.c +++ b/libfreerdp-core/settings.c @@ -97,6 +97,7 @@ rdpSettings* settings_new(void* instance) settings->nla_security = true; settings->tls_security = true; settings->rdp_security = true; + settings->security_layer_negotiation = true; settings->client_build = 2600; settings->kbd_type = 4; /* @msdn{cc240510} 'IBM enhanced (101- or 102-key) keyboard' */ settings->kbd_subtype = 0; diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 1a5b39125..89a1aa1ba 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -122,6 +122,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --disable-full-window-drag: disables full window drag\n" " --disable-menu-animations: disables menu animations\n" " --disable-theming: disables theming\n" + " --no-nego: disable negotiation of security layer and enforce highest enabled security protocol\n" " --no-rdp: disable Standard RDP encryption\n" " --no-tls: disable TLS encryption\n" " --no-nla: disable network level authentication\n" @@ -132,6 +133,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --tsg: Terminal Server Gateway ( )\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? */ @@ -579,6 +582,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, return FREERDP_ARGS_PARSE_FAILURE; } } + else if (strcmp("--no-nego", argv[index]) == 0) + { + settings->security_layer_negotiation = false; + } else if (strcmp("--tsg", argv[index]) == 0) { settings->ts_gateway = true; @@ -698,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);