I have been trying to get started with establishing RDP connections using FreeRDP and after a lot of effort looking at their codebase was able to write a simple script in C.
// main.c
#include <stdio.h>
#include <freerdp/freerdp.h>
#include <winpr/winpr.h>
static BOOL myUpdateBitmap(rdpContext* context, const BITMAP_UPDATE* bitmap) {
return TRUE;
}
static BOOL myBeginPaint(rdpContext* context) {
return TRUE;
}
int main() {
freerdp* instance = freerdp_new();
if (!instance) {
printf("failed to get a freerdp instance\n");
exit(-1);
}
if (!freerdp_context_new(instance)) {
printf("couldn't create a context for the given instance\n");
exit(-1);
}
rdpSettings* settings = instance->settings;
settings->ServerHostname = _strdup("IP");
settings->Username = _strdup("USERNAME");
settings->Password = _strdup("PASSWORD");
settings->Domain = _strdup("DOMAIN");
settings->AsyncInput = TRUE;
settings->ColorDepth = 32;
settings->DesktopWidth = 1024;
settings->DesktopHeight = 768;
settings->IgnoreCertificate = true;
// settings->SupportDynamicTimeZone = true;
instance->update->BitmapUpdate = myUpdateBitmap;
// instance->update->BeginPaint = myBeginPaint;
printf("connecting to rdp server\n");
if (!freerdp_connect(instance)) {
printf("failed to connect to server\n");
exit(-1);
}
printf("connected\n");
while (!freerdp_shall_disconnect(instance)) {
if (freerdp_check_fds(instance) != TRUE) {
printf("Error in freerdp_check_fds(). Disconnecting...\n");
break;
}
// Sleep(10);
}
printf("disconnecting\n");
freerdp_disconnect(instance);
freerdp_context_free(instance);
freerdp_free(instance);
return 0;
}
After running gcc main.c -lfreerdp2 -lwinpr2; ./a.out
, encountering this error
./a.out
connecting to rdp server
[16:09:53:312] [203099:203099] [ERROR][com.winpr.timezone] - Unable to find a match for unix timezone: Asia/Kolkata
connected
[16:09:53:513] [203099:203099] [ERROR][com.freerdp.core.transport] - transport_check_fds: transport->ReceiveCallback() - -4
Error in freerdp_check_fds(). Disconnecting...
disconnecting
which I am not able to fix since hours. Tried searching over the internet, looking at their source code but to no avail and there is no proper documentation regarding proper usage of FreeRDP code. I am able to connect to the target device using mstsc.exe and other tools like Apache Guacamole i.e., there is no network or authentication issue.
Not able to figure out where exactly is the problem occurring and how to fix this. There are very few references regarding FreeRDP so the community inputs will be very helpful!
I am on Kali Linux and have installed the above libraries using,
sudo apt-get install freerdp2-dev;
with header files installed in /usr/include/freerdp2/freerdp/
. Because compiler (gcc) was not able to find #include <freerdp/freerdp.h
, I copied the freerdp
directory from /usr/include/freerdp2/
to /usr/include/
Reference:
Here is the freerdp
implementation in Apache Guacamole,
which works seamlessly.
This code worked
// main.c
#include <stdio.h>
#include <freerdp/freerdp.h>
#include <winpr/winpr.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/gdi/gdi.h>
#include <sys/select.h>
#define ZeroMemory(Destination, Length) memset((Destination), 0, (Length))
static BOOL myUpdateBitmap(rdpContext* context, const BITMAP_UPDATE* bitmap) {
return TRUE;
}
static BOOL myBeginPaint(rdpContext* context) {
return TRUE;
}
static BOOL myMemBltHandler(rdpContext* context, MEMBLT_ORDER* memblt) {
return TRUE;
}
static BOOL myDesktopResize(rdpContext* context) {
return TRUE;
}
static BOOL myEndPaint(rdpContext* context) {
return TRUE;
}
static BOOL mySetBounds(rdpContext* context, const rdpBounds* bounds) {
return TRUE;
}
BOOL myPreConnect(freerdp* instance) {
rdpContext* context = instance->context;
rdpSettings* settings = instance->settings;
settings->ServerHostname = _strdup("IP");
settings->Username = _strdup("USERNAME");
settings->Password = _strdup("PASSWORD");
settings->Domain = _strdup("DOMAIN");
// if you want screen changes, not entire frames
// from the server
// freerdp does not provide this by default
// use the below code
// ZeroMemory(settings->OrderSupport, 32);
// settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
// settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
// settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE;
// settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = TRUE;
// settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
// settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
// settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
settings->AsyncInput = TRUE;
settings->ColorDepth = 32;
settings->AllowFontSmoothing = FALSE;
settings->DisableWallpaper = TRUE;
settings->DisableFullWindowDrag = TRUE;
settings->DisableMenuAnims = TRUE;
settings->DisableThemes = TRUE;
settings->BitmapCacheEnabled = TRUE;
settings->IgnoreCertificate = TRUE;
settings->AuthenticationOnly = FALSE;
if (!settings->ServerPort)
settings->ServerPort = 3389;
if (!gdi_init(instance, PIXEL_FORMAT_BGRA32)) {
return FALSE;
}
instance->update->primary->MemBlt = myMemBltHandler;
instance->update->BeginPaint = myBeginPaint;
instance->update->BitmapUpdate = myUpdateBitmap;
instance->update->DesktopResize = myDesktopResize;
instance->update->EndPaint = myEndPaint;
instance->update->SetBounds = mySetBounds;
return TRUE;
}
BOOL myAuthenticate(freerdp* instance, char** username, char** password, char** domain) {
*username = _strdup("USERNAME");
*password = _strdup("PASSWORD");
*domain = _strdup("DOMAIN");
return TRUE;
}
int main() {
// uncomment below code to get detailed logs
// WLog_SetLogLevel(WLog_GetRoot(), WLOG_TRACE);
freerdp* instance = freerdp_new();
if (!instance) {
fprintf(stderr, "Failed to get a FreeRDP instance\n");
return -1;
}
instance->PreConnect = myPreConnect;
instance->Authenticate = myAuthenticate;
if (!freerdp_context_new(instance)) {
fprintf(stderr, "Couldn't create context\n");
freerdp_free(instance);
return -1;
}
printf("Connecting to RDP server...\n");
if (!freerdp_connect(instance)) {
fprintf(stderr, "Failed to connect to server\n");
freerdp_context_free(instance);
freerdp_free(instance);
return -1;
}
printf("Connected successfully\n");
while (!freerdp_shall_disconnect(instance)) {
if (!freerdp_check_fds(instance)) {
fprintf(stderr, "Failed to check FreeRDP file descriptors\n");
break;
}
}
printf("Disconnecting...\n");
freerdp_disconnect(instance);
freerdp_context_free(instance);
freerdp_free(instance);
return 0;
}
Not sure what made it work, it's most probably these lines of code,
instance->update->DesktopResize = myDesktopResize;
instance->update->EndPaint = myEndPaint;
instance->update->SetBounds = mySetBounds;
Commands to run (on linux),
sudo apt-get install libfreerdp2-dev
gcc main.c -lfreerdp2 -lwinpr2
./a.out