34#include <freerdp/peer.h>
35#include <freerdp/freerdp.h>
36#include <freerdp/settings.h>
37#include <freerdp/constants.h>
38#include <freerdp/crypto/certificate.h>
39#include <freerdp/crypto/privatekey.h>
40#include <freerdp/channels/wtsvc.h>
41#include <freerdp/channels/channels.h>
42#include <freerdp/client.h>
43#include <freerdp/client/cmdline.h>
44#include <freerdp/input.h>
45#include <winpr/tools/makecert.h>
47#include "../multitransport.h"
49#include "TestFuzzServerCerts.h"
52#include <winpr/synch.h>
53#include <winpr/thread.h>
55#include <winpr/path.h>
59#include <netinet/in.h>
65#include <sys/socket.h>
68struct test_peer_context
74typedef struct test_peer_context testPeerContext;
95static void capture_add(capture_t* c,
const void* data,
size_t size)
98 WINPR_ASSERT(data || (size == 0));
100 if (c->len + size > c->cap)
102 size_t ncap = c->cap ? c->cap * 2 : 65536;
103 while (ncap < c->len + size)
105 BYTE* nd = realloc(c->data, ncap);
108 (void)fprintf(stderr,
"capture realloc failed\n");
114 memcpy(c->data + c->len, data, size);
118static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
120 testPeerContext* context = (testPeerContext*)ctx;
121 WINPR_UNUSED(client);
122 if (context && context->vcm)
124 WTSCloseServer(context->vcm);
125 context->vcm =
nullptr;
129static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
131 testPeerContext* context = (testPeerContext*)ctx;
132 WINPR_ASSERT(client);
133 WINPR_ASSERT(context);
134 context->vcm = WTSOpenServerA((LPSTR)client->context);
135 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
139 test_peer_context_free(client, ctx);
143static BOOL test_peer_post_connect(freerdp_peer* peer)
149static BOOL test_peer_activate(freerdp_peer* peer)
155static int test_peer_virtual_channel_read(freerdp_peer* peer, HANDLE hChannel, BYTE* buffer,
159 WINPR_UNUSED(hChannel);
160 WINPR_UNUSED(buffer);
161 WINPR_UNUSED(length);
162 WINPR_ASSERT(buffer || (length == 0));
170static BOOL configure_server(freerdp_peer* client)
172 WINPR_ASSERT(client);
175 char* path = getTestCredentialsFilePath();
176 char* fcert = getTestCredentialsFileNameFor(
"crt");
177 char* fkey = getTestCredentialsFileNameFor(
"key");
178 if (!path || !fcert || !fkey)
181 client->ContextSize =
sizeof(testPeerContext);
182 client->ContextNew = test_peer_context_new;
183 client->ContextFree = test_peer_context_free;
184 if (!freerdp_peer_context_new(client))
187 WINPR_ASSERT(client->context);
188 rdpSettings* settings = client->context->settings;
189 WINPR_ASSERT(settings);
191 rdpCertificate* cert = freerdp_certificate_new_from_file(fcert);
197 rdpPrivateKey* key = freerdp_key_new_from_file(fkey);
229 INITIATE_REQUEST_PROTOCOL_UDPFECR))
234 client->PostConnect = test_peer_post_connect;
235 client->Activate = test_peer_activate;
236 client->VirtualChannelRead = test_peer_virtual_channel_read;
239 client->local = TRUE;
240 if (!client->Initialize(client))
252static DWORD WINAPI peer_thread(LPVOID arg)
254 freerdp_peer* client = ((peer_arg_t*)arg)->client;
255 DWORD error = CHANNEL_RC_OK;
257 if (!configure_server(client))
259 freerdp_peer_context_free(client);
260 freerdp_peer_free(client);
264 testPeerContext* context = (testPeerContext*)client->context;
265 WINPR_ASSERT(context);
267 while (error == CHANNEL_RC_OK)
269 HANDLE handles[32] = WINPR_C_ARRAY_INIT;
271 DWORD tmp = client->GetEventHandles(client, &handles[count], ARRAYSIZE(handles) - count);
275 handles[count++] = WTSVirtualChannelManagerGetEventHandle(context->vcm);
276 DWORD status = WaitForMultipleObjects(count, handles, FALSE, 5000);
277 if (status == WAIT_FAILED || status == WAIT_TIMEOUT)
279 if (client->CheckFileDescriptor(client) != TRUE)
281 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
285 client->Disconnect(client);
286 freerdp_peer_context_free(client);
287 freerdp_peer_free(client);
291static void* relay_c2s(
void* arg)
293 relay_arg_t* a = (relay_arg_t*)arg;
294 BYTE buf[65536] = WINPR_C_ARRAY_INIT;
297 ssize_t rc = read(a->client_sock, buf,
sizeof(buf));
300 capture_add(a->capture, buf, (
size_t)rc);
301 ssize_t w = write(a->peer_sock, buf, (
size_t)rc);
305 shutdown(a->peer_sock, SHUT_WR);
309static void* relay_s2c(
void* arg)
311 relay_arg_t* a = (relay_arg_t*)arg;
312 BYTE buf[65536] = WINPR_C_ARRAY_INIT;
315 ssize_t rc = read(a->peer_sock, buf,
sizeof(buf));
318 ssize_t w = write(a->client_sock, buf, (
size_t)rc);
322 shutdown(a->client_sock, SHUT_WR);
332static DWORD WINAPI client_thread(LPVOID arg)
334 client_arg_t* a = (client_arg_t*)arg;
335 char arg1[64] = WINPR_C_ARRAY_INIT;
336 (void)snprintf(arg1,
sizeof(arg1),
"/v:127.0.0.1:%d", a->port);
337 char* argv[] = {
"seedgen", arg1,
"/sec:rdp",
"/cert:ignore",
"/rfx",
nullptr };
340 RDP_CLIENT_ENTRY_POINTS entry = WINPR_C_ARRAY_INIT;
341 entry.Size =
sizeof(RDP_CLIENT_ENTRY_POINTS);
342 entry.Version = RDP_CLIENT_INTERFACE_VERSION;
343 entry.ContextSize =
sizeof(rdpContext);
345 rdpContext* context = freerdp_client_context_new(&entry);
363 if (freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE) < 0)
366 if (!freerdp_connect(context->instance))
368 (void)fprintf(stderr,
"client connect failed\n");
374 rdpInput* input = context->input;
376 for (
int i = 0; i < 3; i++)
378 freerdp_input_send_synchronize_event(input, 0);
379 freerdp_input_send_keyboard_event(input, KBD_FLAGS_DOWN, 0x1e);
380 freerdp_input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x1e);
381 freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 100 + i * 10, 100);
382 freerdp_input_send_mouse_event(input, PTR_FLAGS_BUTTON1, 100 + i * 10, 100);
388 freerdp_disconnect(context->instance);
389 freerdp_client_context_free(context);
395static int write_seed(
const char* dir,
const char* name,
const capture_t* c)
397 char path[512] = WINPR_C_ARRAY_INIT;
398 (void)snprintf(path,
sizeof(path),
"%s/%s", dir, name);
399 FILE* f = fopen(path,
"wb");
402 size_t w = fwrite(c->data, 1, c->len, f);
404 return (w == c->len) ? 0 : -1;
407int main(
int argc,
char** argv)
409 (void)signal(SIGPIPE, SIG_IGN);
411 const char* outdir = argc > 1 ? argv[1] :
".";
416 const unsigned long val = strtoul(argv[2],
nullptr, 0);
417 if ((errno != 0) || (val > INT_MAX))
422 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
423 (void)winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
425 int lfd = socket(AF_INET, SOCK_STREAM, 0);
429 setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &one,
sizeof(one));
430 struct sockaddr_in sa = WINPR_C_ARRAY_INIT;
431 sa.sin_family = AF_INET;
432 sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
434 if (bind(lfd, (
struct sockaddr*)&sa,
sizeof(sa)) != 0)
436 if (listen(lfd, 4) != 0)
438 socklen_t slen =
sizeof(sa);
439 getsockname(lfd, (
struct sockaddr*)&sa, &slen);
440 int port = ntohs(sa.sin_port);
441 printf(
"listening on 127.0.0.1:%d\n", port);
443 client_arg_t carg = { port, do_input };
444 HANDLE hclient = CreateThread(
nullptr, 0, client_thread, &carg, 0,
nullptr);
446 int cfd = accept(lfd,
nullptr,
nullptr);
449 printf(
"client connected\n");
451 int sv[2] = WINPR_C_ARRAY_INIT;
452 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0)
455 freerdp_peer* client = freerdp_peer_new(sv[0]);
459 capture_t capture = WINPR_C_ARRAY_INIT;
460 relay_arg_t ra = { cfd, sv[1], &capture };
462 pthread_t t1 = WINPR_C_ARRAY_INIT;
463 pthread_create(&t1,
nullptr, relay_c2s, &ra);
464 pthread_t t2 = WINPR_C_ARRAY_INIT;
465 pthread_create(&t2,
nullptr, relay_s2c, &ra);
467 peer_arg_t pa = { client };
468 HANDLE hpeer = CreateThread(
nullptr, 0, peer_thread, &pa, 0,
nullptr);
470 WaitForSingleObject(hclient, 30000);
477 pthread_join(t1,
nullptr);
478 pthread_join(t2,
nullptr);
480 WaitForSingleObject(hpeer, 10000);
482 CloseHandle(hclient);
486 printf(
"captured %zu bytes\n", capture.len);
488 if (capture.len == 0)
492 write_seed(outdir,
"handshake", &capture);
496 static const size_t cuts[] = { 64, 128, 256, 512, 1024 };
497 for (
size_t i = 0; i <
sizeof(cuts) /
sizeof(cuts[0]); i++)
499 if (capture.len > cuts[i])
501 char name[64] = WINPR_C_ARRAY_INIT;
502 capture_t t = WINPR_C_ARRAY_INIT;
503 t.data = capture.data;
505 (void)snprintf(name,
sizeof(name),
"handshake_cut%zu", cuts[i]);
506 write_seed(outdir, name, &t);
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.