summaryrefslogtreecommitdiffstats
path: root/libxrdp/xrdp_rdp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libxrdp/xrdp_rdp.c')
-rw-r--r--libxrdp/xrdp_rdp.c323
1 files changed, 299 insertions, 24 deletions
diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c
index bdbeed48..53e3ddc2 100644
--- a/libxrdp/xrdp_rdp.c
+++ b/libxrdp/xrdp_rdp.c
@@ -24,6 +24,7 @@
#if defined(XRDP_FREERDP1)
#include <freerdp/codec/mppc_enc.h>
+#include <freerdp/codec/rfx.h>
#endif
/* some compilers need unsigned char to avoid warnings */
@@ -113,13 +114,25 @@ xrdp_rdp_read_config(struct xrdp_client_info* client_info)
{
client_info->crypt_level = 3;
}
+ else
+ {
+ g_writeln("Warning: Your configured crypt level is"
+ "undefined 'high' will be used");
+ client_info->crypt_level = 3;
+ }
}
else if (g_strcasecmp(item, "channel_code") == 0)
{
- if (g_strcasecmp(value, "1") == 0)
+ if ((g_strcasecmp(value, "yes") == 0) ||
+ (g_strcasecmp(value, "1") == 0) ||
+ (g_strcasecmp(value, "true") == 0))
{
client_info->channel_code = 1;
}
+ else
+ {
+ g_writeln("Info: All channels are disabled");
+ }
}
else if (g_strcasecmp(item, "max_bpp") == 0)
{
@@ -131,11 +144,66 @@ xrdp_rdp_read_config(struct xrdp_client_info* client_info)
return 0;
}
+#if defined(XRDP_FREERDP1)
+/*****************************************************************************/
+static void
+cpuid(tui32 info, tui32* eax, tui32* ebx, tui32* ecx, tui32* edx)
+{
+#ifdef __GNUC__
+#if defined(__i386__) || defined(__x86_64__)
+ __asm volatile
+ (
+ /* The EBX (or RBX register on x86_64) is used for the PIC base address
+ and must not be corrupted by our inline assembly. */
+#if defined(__i386__)
+ "mov %%ebx, %%esi;"
+ "cpuid;"
+ "xchg %%ebx, %%esi;"
+#else
+ "mov %%rbx, %%rsi;"
+ "cpuid;"
+ "xchg %%rbx, %%rsi;"
+#endif
+ : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (info)
+ );
+#endif
+#endif
+}
+
+/*****************************************************************************/
+static tui32
+xrdp_rdp_detect_cpu(void)
+{
+ tui32 eax;
+ tui32 ebx;
+ tui32 ecx;
+ tui32 edx;
+ tui32 cpu_opt;
+
+ eax = 0;
+ ebx = 0;
+ ecx = 0;
+ edx = 0;
+ cpu_opt = 0;
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+
+ if (edx & (1 << 26))
+ {
+ DEBUG("SSE2 detected");
+ cpu_opt |= CPU_SSE2;
+ }
+
+ return cpu_opt;
+}
+#endif
+
/*****************************************************************************/
struct xrdp_rdp* APP_CC
xrdp_rdp_create(struct xrdp_session* session, struct trans* trans)
{
struct xrdp_rdp* self = (struct xrdp_rdp *)NULL;
+ int bytes;
DEBUG(("in xrdp_rdp_create"));
self = (struct xrdp_rdp*)g_malloc(sizeof(struct xrdp_rdp), 1);
@@ -153,9 +221,13 @@ xrdp_rdp_create(struct xrdp_session* session, struct trans* trans)
self->client_info.cache2_size = 1024;
self->client_info.cache3_entries = 262;
self->client_info.cache3_size = 4096;
- g_write_ip_address(trans->sck, self->client_info.client_ip); /* load client ip info */
+ /* load client ip info */
+ bytes = sizeof(self->client_info.client_ip) - 1;
+ g_write_ip_address(trans->sck, self->client_info.client_ip, bytes);
#if defined(XRDP_FREERDP1)
self->mppc_enc = mppc_enc_new(PROTO_RDP_50);
+ self->rfx_enc = rfx_context_new();
+ rfx_context_set_cpu_opt(self->rfx_enc, xrdp_rdp_detect_cpu());
#endif
self->client_info.size = sizeof(self->client_info);
DEBUG(("out xrdp_rdp_create"));
@@ -173,6 +245,7 @@ xrdp_rdp_delete(struct xrdp_rdp* self)
xrdp_sec_delete(self->sec_layer);
#if defined(XRDP_FREERDP1)
mppc_enc_free((struct rdp_mppc_enc*)(self->mppc_enc));
+ rfx_context_free((RFX_CONTEXT*)(self->rfx_enc));
#endif
g_free(self);
}
@@ -220,7 +293,7 @@ xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code)
{
s->next_packet = 0;
*code = -1;
- DEBUG(("out xrdp_rdp_recv"));
+ DEBUG(("out (1) xrdp_rdp_recv"));
return 0;
}
if (error != 0)
@@ -232,35 +305,47 @@ xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code)
{
if (chan > MCS_GLOBAL_CHANNEL)
{
- xrdp_channel_process(self->sec_layer->chan_layer, s, chan);
+ if(xrdp_channel_process(self->sec_layer->chan_layer, s, chan)!=0)
+ {
+ g_writeln("xrdp_channel_process returned unhandled error") ;
+ }
+ }
+ else
+ {
+ g_writeln("Wrong channel Id to be handled by xrdp_channel_process %d",chan);
}
s->next_packet = 0;
*code = 0;
- DEBUG(("out xrdp_rdp_recv"));
+ DEBUG(("out (2) xrdp_rdp_recv"));
return 0;
}
s->next_packet = s->p;
}
else
{
+ DEBUG(("xrdp_rdp_recv stream not touched"))
s->p = s->next_packet;
}
if (!s_check_rem(s, 6))
{
s->next_packet = 0;
*code = 0;
- DEBUG(("out xrdp_rdp_recv"));
+ DEBUG(("out (3) xrdp_rdp_recv"));
len = (int)(s->end - s->p);
g_writeln("xrdp_rdp_recv: bad RDP packet, length [%d]", len);
return 0;
}
- in_uint16_le(s, len);
- in_uint16_le(s, pdu_code);
- *code = pdu_code & 0xf;
- in_uint8s(s, 2); /* mcs user id */
- s->next_packet += len;
- DEBUG(("out xrdp_rdp_recv"));
- return 0;
+ else
+ {
+ in_uint16_le(s, len);
+ /*g_writeln("New len received : %d next packet: %d s_end: %d",len,s->next_packet,s->end); */
+ in_uint16_le(s, pdu_code);
+ *code = pdu_code & 0xf;
+ in_uint8s(s, 2); /* mcs user id */
+ s->next_packet += len;
+ DEBUG(("out (4) xrdp_rdp_recv"));
+ return 0;
+ }
}
/*****************************************************************************/
@@ -318,7 +403,7 @@ xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s,
if (self->client_info.rdp_compression && self->session->up_and_running)
{
mppc_enc = (struct rdp_mppc_enc*)(self->mppc_enc);
- if (compress_rdp(mppc_enc, s->p + 18, tocomplen))
+ if (compress_rdp(mppc_enc, (tui8*)(s->p + 18), tocomplen))
{
DEBUG(("mppc_encode ok flags 0x%x bytes_in_opb %d historyOffset %d "
"tocomplen %d", mppc_enc->flags, mppc_enc->bytes_in_opb,
@@ -474,9 +559,13 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp* self)
struct stream* s;
int caps_count;
int caps_size;
+ int codec_caps_count;
+ int codec_caps_size;
char* caps_count_ptr;
char* caps_size_ptr;
char* caps_ptr;
+ char* codec_caps_count_ptr;
+ char* codec_caps_size_ptr;
make_stream(s);
init_stream(s, 8192);
@@ -589,12 +678,48 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp* self)
out_uint8(s, 0); /* unused */
out_uint8(s, 0); /* unused */
out_uint16_le(s, 0x6a1);
- out_uint8s(s, 2); /* ? */
+ /* declare support of bitmap cache rev3 */
+ out_uint16_le(s, XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT);
out_uint32_le(s, 0x0f4240); /* desk save */
out_uint32_le(s, 0x0f4240); /* desk save */
out_uint32_le(s, 1); /* ? */
out_uint32_le(s, 0); /* ? */
+ /* Output bmpcodecs capability set */
+ caps_count++;
+ out_uint16_le(s, RDP_CAPSET_BMPCODECS);
+ codec_caps_size_ptr = s->p;
+ out_uint8s(s, 2); /* cap len set later */
+ codec_caps_count = 0;
+ codec_caps_count_ptr = s->p;
+ out_uint8s(s, 1); /* bitmapCodecCount set later */
+ /* nscodec */
+ codec_caps_count++;
+ out_uint8a(s, XR_CODEC_GUID_NSCODEC, 16);
+ out_uint8(s, 1); /* codec id, must be 1 */
+ out_uint16_le(s, 3);
+ out_uint8(s, 0x01); /* fAllowDynamicFidelity */
+ out_uint8(s, 0x01); /* fAllowSubsampling */
+ out_uint8(s, 0x03); /* colorLossLevel */
+ /* remotefx */
+ codec_caps_count++;
+ out_uint8a(s, XR_CODEC_GUID_REMOTEFX, 16);
+ out_uint8(s, 0); /* codec id, client sets */
+ out_uint16_le(s, 256);
+ out_uint8s(s, 256);
+ /* jpeg */
+ codec_caps_count++;
+ out_uint8a(s, XR_CODEC_GUID_JPEG, 16);
+ out_uint8(s, 0); /* codec id, client sets */
+ out_uint16_le(s, 1); /* ext length */
+ out_uint8(s, 75);
+ /* calculate and set size and count */
+ codec_caps_size = (int)(s->p - codec_caps_size_ptr);
+ codec_caps_size += 2; /* 2 bytes for RDP_CAPSET_BMPCODECS above */
+ codec_caps_size_ptr[0] = codec_caps_size;
+ codec_caps_size_ptr[1] = codec_caps_size >> 8;
+ codec_caps_count_ptr[0] = codec_caps_count;
+
/* Output color cache capability set */
caps_count++;
out_uint16_le(s, RDP_CAPSET_COLCACHE);
@@ -617,6 +742,27 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp* self)
out_uint8(s, 1);
out_uint8s(s, 83);
+ /* Remote Programs Capability Set */
+ caps_count++;
+ out_uint16_le(s, 0x0017); /* CAPSETTYPE_RAIL */
+ out_uint16_le(s, 8);
+ out_uint32_le(s, 3); /* TS_RAIL_LEVEL_SUPPORTED
+ TS_RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED */
+
+ /* Window List Capability Set */
+ caps_count++;
+ out_uint16_le(s, 0x0018); /* CAPSETTYPE_WINDOW */
+ out_uint16_le(s, 11);
+ out_uint32_le(s, 2); /* TS_WINDOW_LEVEL_SUPPORTED_EX */
+ out_uint8(s, 3); /* NumIconCaches */
+ out_uint16_le(s, 12); /* NumIconCacheEntries */
+
+ /* 6 - bitmap cache v3 codecid */
+ caps_count++;
+ out_uint16_le(s, 0x0006);
+ out_uint16_le(s, 5);
+ out_uint8(s, 0); /* client sets */
+
out_uint8s(s, 4); /* pad */
s_mark_end(s);
@@ -664,6 +810,7 @@ xrdp_process_capset_order(struct xrdp_rdp* self, struct stream* s,
{
int i;
char order_caps[32];
+ int ex_flags;
DEBUG(("order capabilities"));
in_uint8s(s, 20); /* Terminal desc, pad */
@@ -694,7 +841,15 @@ xrdp_process_capset_order(struct xrdp_rdp* self, struct stream* s,
g_hexdump(order_caps, 32);
#endif
in_uint8s(s, 2); /* Text capability flags */
- in_uint8s(s, 6); /* Pad */
+ /* read extended order support flags */
+ in_uint16_le(s, ex_flags); /* Ex flags */
+ if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT)
+ {
+ g_writeln("xrdp_process_capset_order: bitmap cache v3 supported");
+ self->client_info.bitmap_cache_version |= 4;
+ }
+ in_uint8s(s, 4); /* Pad */
+
in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */
self->client_info.desktop_cache = i;
DEBUG(("desktop cache size %d", i));
@@ -709,6 +864,7 @@ static int APP_CC
xrdp_process_capset_bmpcache(struct xrdp_rdp* self, struct stream* s,
int len)
{
+ self->client_info.bitmap_cache_version |= 1;
in_uint8s(s, 24);
in_uint16_le(s, self->client_info.cache1_entries);
in_uint16_le(s, self->client_info.cache1_size);
@@ -734,16 +890,9 @@ xrdp_process_capset_bmpcache2(struct xrdp_rdp* self, struct stream* s,
int Bpp = 0;
int i = 0;
- self->client_info.bitmap_cache_version = 2;
+ self->client_info.bitmap_cache_version |= 2;
Bpp = (self->client_info.bpp + 7) / 8;
in_uint16_le(s, i); /* cache flags */
-#if defined(XRDP_JPEG)
- if (i & 0x80)
- {
- g_writeln("xrdp_process_capset_bmpcache2: client supports jpeg");
- self->client_info.jpeg = 1;
- }
-#endif
self->client_info.bitmap_cache_persist_enable = i;
in_uint8s(s, 2); /* number of caches in set, 3 */
in_uint32_le(s, i);
@@ -769,6 +918,20 @@ xrdp_process_capset_bmpcache2(struct xrdp_rdp* self, struct stream* s,
}
/*****************************************************************************/
+static int
+xrdp_process_capset_cache_v3_codec_id(struct xrdp_rdp* self, struct stream* s,
+ int len)
+{
+ int codec_id;
+
+ in_uint8(s, codec_id);
+ g_writeln("xrdp_process_capset_cache_v3_codec_id: cache_v3_codec_id %d",
+ codec_id);
+ self->client_info.v3_codec_id = codec_id;
+ return 0;
+}
+
+/*****************************************************************************/
/* get the number of client cursor cache */
static int APP_CC
xrdp_process_capset_pointercache(struct xrdp_rdp* self, struct stream* s,
@@ -823,6 +986,106 @@ xrdp_process_offscreen_bmpcache(struct xrdp_rdp* self, struct stream* s,
}
/*****************************************************************************/
+static int APP_CC
+xrdp_process_capset_rail(struct xrdp_rdp* self, struct stream* s, int len)
+{
+ int i32;
+
+ if (len - 4 < 4)
+ {
+ g_writeln("xrdp_process_capset_rail: bad len");
+ return 1;
+ }
+ in_uint32_le(s, i32);
+ self->client_info.rail_support_level = i32;
+ g_writeln("xrdp_process_capset_rail: rail_support_level %d",
+ self->client_info.rail_support_level);
+ return 0;
+}
+
+/*****************************************************************************/
+static int APP_CC
+xrdp_process_capset_window(struct xrdp_rdp* self, struct stream* s, int len)
+{
+ int i32;
+
+ if (len - 4 < 7)
+ {
+ g_writeln("xrdp_process_capset_window: bad len");
+ return 1;
+ }
+ in_uint32_le(s, i32);
+ self->client_info.wnd_support_level = i32;
+ in_uint8(s, i32);
+ self->client_info.wnd_num_icon_caches = i32;
+ in_uint16_le(s, i32);
+ self->client_info.wnd_num_icon_cache_entries = i32;
+ g_writeln("xrdp_process_capset_window wnd_support_level %d "
+ "wnd_num_icon_caches %d wnd_num_icon_cache_entries %d",
+ self->client_info.wnd_support_level,
+ self->client_info.wnd_num_icon_caches,
+ self->client_info.wnd_num_icon_cache_entries);
+ return 0;
+}
+
+/*****************************************************************************/
+static int APP_CC
+xrdp_process_capset_codecs(struct xrdp_rdp* self, struct stream* s, int len)
+{
+ int codec_id;
+ int codec_count;
+ int index;
+ int codec_properties_length;
+ int i1;
+ char* codec_guid;
+ char* next_guid;
+
+ in_uint8(s, codec_count);
+ for (index = 0; index < codec_count; index++)
+ {
+ codec_guid = s->p;
+ in_uint8s(s, 16);
+ in_uint8(s, codec_id);
+ in_uint16_le(s, codec_properties_length);
+ next_guid = s->p + codec_properties_length;
+ if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0)
+ {
+ g_writeln("xrdp_process_capset_codecs: nscodec codec id %d prop len %d",
+ codec_id, codec_properties_length);
+ self->client_info.ns_codec_id = codec_id;
+ i1 = MIN(64, codec_properties_length);
+ g_memcpy(self->client_info.ns_prop, s->p, i1);
+ self->client_info.ns_prop_len = i1;
+ }
+ else if (g_memcmp(codec_guid, XR_CODEC_GUID_REMOTEFX, 16) == 0)
+ {
+ g_writeln("xrdp_process_capset_codecs: rfx codec id %d prop len %d",
+ codec_id, codec_properties_length);
+ self->client_info.rfx_codec_id = codec_id;
+ i1 = MIN(64, codec_properties_length);
+ g_memcpy(self->client_info.rfx_prop, s->p, i1);
+ self->client_info.rfx_prop_len = i1;
+ }
+ else if (g_memcmp(codec_guid, XR_CODEC_GUID_JPEG, 16) == 0)
+ {
+ g_writeln("xrdp_process_capset_codecs: jpeg codec id %d prop len %d",
+ codec_id, codec_properties_length);
+ self->client_info.jpeg_codec_id = codec_id;
+ i1 = MIN(64, codec_properties_length);
+ g_memcpy(self->client_info.jpeg_prop, s->p, i1);
+ self->client_info.jpeg_prop_len = i1;
+ g_writeln(" jpeg quality %d", self->client_info.jpeg_prop[0]);
+ }
+ else
+ {
+ g_writeln("xrdp_process_capset_codecs: unknown codec id %d", codec_id);
+ }
+ s->p = next_guid;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
int APP_CC
xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s)
{
@@ -867,6 +1130,9 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s)
case RDP_CAPSET_CONTROL: /* 5 */
DEBUG(("RDP_CAPSET_CONTROL"));
break;
+ case 6:
+ xrdp_process_capset_cache_v3_codec_id(self, s, len);
+ break;
case RDP_CAPSET_ACTIVATE: /* 7 */
DEBUG(("RDP_CAPSET_ACTIVATE"));
break;
@@ -912,9 +1178,18 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s)
case 22: /* 22 */
DEBUG(("--22"));
break;
+ case 0x0017: /* 23 CAPSETTYPE_RAIL */
+ xrdp_process_capset_rail(self, s, len);
+ break;
+ case 0x0018: /* 24 CAPSETTYPE_WINDOW */
+ xrdp_process_capset_window(self, s, len);
+ break;
case 26: /* 26 */
DEBUG(("--26"));
break;
+ case RDP_CAPSET_BMPCODECS: /* 0x1d(29) */
+ xrdp_process_capset_codecs(self, s, len);
+ break;
default:
g_writeln("unknown in xrdp_rdp_process_confirm_active %d", type);
break;