Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/freerdp.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * FreeRDP Core
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include "settings.h"
25
26
#include <string.h>
27
#include <stdarg.h>
28
#include <time.h>
29
30
#include "rdp.h"
31
#include "input.h"
32
#include "update.h"
33
#include "surface.h"
34
#include "transport.h"
35
#include "connection.h"
36
#include "message.h"
37
#include <freerdp/buildflags.h>
38
#include "gateway/rpc_fault.h"
39
#include "../cache/cache.h"
40
41
#include <winpr/assert.h>
42
43
#include <winpr/crt.h>
44
#include <winpr/string.h>
45
#include <winpr/stream.h>
46
#include <winpr/wtsapi.h>
47
#include <winpr/ssl.h>
48
#include <winpr/debug.h>
49
#include <winpr/i18n.h>
50
51
#include <freerdp/freerdp.h>
52
#include <freerdp/streamdump.h>
53
#include <freerdp/error.h>
54
#include <freerdp/event.h>
55
#include <freerdp/locale/keyboard.h>
56
#include <freerdp/locale/locale.h>
57
#include <freerdp/channels/channels.h>
58
#include <freerdp/version.h>
59
#include <freerdp/log.h>
60
#include <freerdp/utils/signal.h>
61
62
#include "../cache/pointer.h"
63
#include "utils.h"
64
65
14.3k
#define TAG FREERDP_TAG("core")
66
67
BOOL freerdp_enable_translation(const char* locale, const char* searchPath)
68
0
{
69
0
  return winpr_i18n_enable_translation(locale) && winpr_i18n_bind_domain("freerdp", searchPath);
70
0
}
71
72
static void sig_abort_connect(int signum, const char* signame, void* ctx)
73
0
{
74
0
  rdpContext* context = (rdpContext*)ctx;
75
76
0
  WLog_INFO(TAG, "Signal %s [%d], terminating session %p", signame, signum,
77
0
            WINPR_CXX_COMPAT_CAST(const void*, context));
78
0
  if (context)
79
0
    freerdp_abort_connect_context(context);
80
0
}
81
82
/** Creates a new connection based on the settings found in the "instance" parameter
83
 *  It will use the callbacks registered on the structure to process the pre/post connect operations
84
 *  that the caller requires.
85
 *  @see struct rdp_freerdp in freerdp.h
86
 *
87
 *  @param instance - pointer to a rdp_freerdp structure that contains base information to establish
88
 * the connection. On return, this function will be initialized with the new connection's settings.
89
 *
90
 *  @return TRUE if successful. FALSE otherwise.
91
 *
92
 */
93
static int freerdp_connect_begin(freerdp* instance)
94
0
{
95
0
  BOOL rc = 0;
96
0
  rdpRdp* rdp = nullptr;
97
0
  BOOL status = TRUE;
98
0
  rdpSettings* settings = nullptr;
99
100
0
  if (!instance)
101
0
    return -1;
102
103
0
  WINPR_ASSERT(instance->context);
104
105
  /* We always set the return code to 0 before we start the connect sequence*/
106
0
  instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
107
0
  freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
108
0
  clearChannelError(instance->context);
109
0
  if (!utils_reset_abort(instance->context->rdp))
110
0
    return -1;
111
112
0
  rdp = instance->context->rdp;
113
0
  WINPR_ASSERT(rdp);
114
115
0
  settings = instance->context->settings;
116
0
  WINPR_ASSERT(settings);
117
118
0
  freerdp_channels_register_instance(instance->context->channels, instance);
119
120
0
  if (!freerdp_settings_set_default_order_support(settings))
121
0
    return -1;
122
123
0
  if (!freerdp_add_signal_cleanup_handler(instance->context, sig_abort_connect))
124
0
    return -1;
125
126
0
  IFCALLRET(instance->PreConnect, status, instance);
127
0
  instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
128
129
0
  freerdp_settings_print_warnings(settings);
130
0
  if (status)
131
0
    status = freerdp_settings_enforce_monitor_exists(settings);
132
133
0
  if (status)
134
0
    status = freerdp_settings_enforce_consistency(settings);
135
136
0
  if (status)
137
0
    status = freerdp_settings_check_client_after_preconnect(settings);
138
139
0
  if (status)
140
0
    status = rdp_set_backup_settings(rdp);
141
0
  if (status)
142
0
    status = utils_reload_channels(instance->context);
143
144
0
  const UINT32 cp = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardCodePage);
145
0
  int64_t KeyboardLayout = freerdp_get_keyboard_default_layout_for_locale(cp);
146
0
  if (KeyboardLayout == 0)
147
0
    KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
148
149
0
  switch (KeyboardLayout)
150
0
  {
151
0
    case KBD_JAPANESE:
152
0
    case KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002:
153
0
    {
154
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType,
155
0
                                       WINPR_KBD_TYPE_JAPANESE))
156
0
        return -1;
157
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 2))
158
0
        return -1;
159
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12))
160
0
        return -1;
161
0
    }
162
0
    break;
163
0
    default:
164
0
      break;
165
0
  }
166
167
0
  if (!status)
168
0
  {
169
0
    rdpContext* context = instance->context;
170
0
    WINPR_ASSERT(context);
171
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_PRE_CONNECT_FAILED);
172
173
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_pre_connect failed: %s",
174
0
               rdp_client_connection_state_string(instance->ConnectionCallbackState));
175
0
    return 0;
176
0
  }
177
178
0
  rc = rdp_client_connect(rdp);
179
180
  /* --authonly tests the connection without a UI */
181
0
  if (freerdp_settings_get_bool(rdp->settings, FreeRDP_AuthenticationOnly))
182
0
  {
183
0
    rdpContext* context = rdp->context;
184
0
    WINPR_ASSERT(context);
185
0
    WLog_Print(context->log, WLOG_ERROR, "Authentication only, exit status %" PRId32 "", rc);
186
0
    return 0;
187
0
  }
188
189
0
  return rc ? 1 : 0;
190
0
}
191
192
BOOL freerdp_connect(freerdp* instance)
193
0
{
194
0
  BOOL status = FALSE;
195
0
  ConnectionResultEventArgs e = WINPR_C_ARRAY_INIT;
196
0
  const int rc = freerdp_connect_begin(instance);
197
0
  rdpRdp* rdp = nullptr;
198
0
  UINT status2 = ERROR_INTERNAL_ERROR;
199
200
0
  WINPR_ASSERT(instance);
201
0
  WINPR_ASSERT(instance->context);
202
203
0
  rdp = instance->context->rdp;
204
0
  WINPR_ASSERT(rdp);
205
0
  WINPR_ASSERT(rdp->settings);
206
207
0
  if (rc > 0)
208
  /* Pointers might have changed in between */
209
0
  {
210
0
    rdp_update_internal* up = update_cast(rdp->update);
211
212
0
    if (freerdp_settings_get_bool(rdp->settings, FreeRDP_DumpRemoteFx))
213
0
    {
214
0
      up->pcap_rfx = pcap_open(
215
0
          freerdp_settings_get_string(rdp->settings, FreeRDP_DumpRemoteFxFile), TRUE);
216
217
0
      if (up->pcap_rfx)
218
0
        up->dump_rfx = TRUE;
219
0
    }
220
221
0
    pointer_cache_register_callbacks(instance->context->update);
222
0
    status = IFCALLRESULT(TRUE, instance->PostConnect, instance);
223
0
    instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
224
225
0
    if (status)
226
0
      status2 = freerdp_channels_post_connect(instance->context->channels, instance);
227
0
  }
228
0
  else
229
0
  {
230
0
    status2 = CHANNEL_RC_OK;
231
0
    if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
232
0
      status = freerdp_reconnect(instance);
233
0
    else
234
0
      goto freerdp_connect_finally;
235
0
  }
236
237
0
  if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->context->update))
238
0
  {
239
0
    rdpContext* context = instance->context;
240
0
    WINPR_ASSERT(context);
241
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_post_connect failed");
242
243
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_POST_CONNECT_FAILED);
244
245
0
    status = FALSE;
246
0
    goto freerdp_connect_finally;
247
0
  }
248
249
0
  if (freerdp_settings_get_bool(rdp->settings, FreeRDP_PlayRemoteFx))
250
0
  {
251
0
    wStream* s = nullptr;
252
0
    rdp_update_internal* update = update_cast(instance->context->update);
253
0
    pcap_record record = WINPR_C_ARRAY_INIT;
254
255
0
    WINPR_ASSERT(update);
256
0
    const char* PlayRemoteFxFile =
257
0
        freerdp_settings_get_string(rdp->settings, FreeRDP_PlayRemoteFxFile);
258
0
    update->pcap_rfx = pcap_open(PlayRemoteFxFile, FALSE);
259
0
    status = FALSE;
260
261
0
    if (!update->pcap_rfx)
262
0
      goto freerdp_connect_finally;
263
0
    else
264
0
      update->play_rfx = TRUE;
265
266
0
    status = TRUE;
267
268
0
    while (pcap_has_next_record(update->pcap_rfx) && status)
269
0
    {
270
0
      if (!pcap_get_next_record_header(update->pcap_rfx, &record))
271
0
        break;
272
273
0
      s = transport_take_from_pool(rdp->transport, record.length);
274
0
      if (!s)
275
0
        break;
276
277
0
      record.data = Stream_Buffer(s);
278
0
      if (!pcap_get_next_record_content(update->pcap_rfx, &record))
279
0
        break;
280
0
      if (!Stream_SetLength(s, record.length))
281
0
      {
282
0
        status = FALSE;
283
0
        continue;
284
0
      }
285
0
      Stream_ResetPosition(s);
286
287
0
      if (!update_begin_paint(&update->common))
288
0
        status = FALSE;
289
0
      else
290
0
      {
291
0
        if (!update_recv_surfcmds(&update->common, s))
292
0
          status = FALSE;
293
294
0
        if (!update_end_paint(&update->common))
295
0
          status = FALSE;
296
0
      }
297
298
0
      Stream_Release(s);
299
0
    }
300
301
0
    pcap_close(update->pcap_rfx);
302
0
    update->pcap_rfx = nullptr;
303
0
    goto freerdp_connect_finally;
304
0
  }
305
306
0
  if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
307
0
    freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
308
309
0
  if (status)
310
0
    status = transport_set_connected_event(rdp->transport);
311
312
0
freerdp_connect_finally:
313
0
  EventArgsInit(&e, "freerdp");
314
0
  e.result = status ? 0 : -1;
315
0
  if (PubSub_OnConnectionResult(rdp->pubSub, instance->context, &e) < 0)
316
0
    return FALSE;
317
318
0
  if (!status)
319
0
    freerdp_disconnect(instance);
320
321
0
  return status;
322
0
}
323
324
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
325
BOOL freerdp_abort_connect(freerdp* instance)
326
0
{
327
0
  if (!instance)
328
0
    return FALSE;
329
330
0
  return freerdp_abort_connect_context(instance->context);
331
0
}
332
#endif
333
334
BOOL freerdp_abort_connect_context(rdpContext* context)
335
0
{
336
0
  if (!context)
337
0
    return FALSE;
338
339
0
  freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
340
0
  return utils_abort_connect(context->rdp);
341
0
}
342
343
#if defined(WITH_FREERDP_DEPRECATED)
344
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, WINPR_ATTR_UNUSED void** wfds,
345
                     WINPR_ATTR_UNUSED int* wcount)
346
{
347
  rdpRdp* rdp = nullptr;
348
349
  WINPR_ASSERT(instance);
350
  WINPR_ASSERT(instance->context);
351
352
  rdp = instance->context->rdp;
353
  WINPR_ASSERT(rdp);
354
355
  transport_get_fds(rdp->transport, rfds, rcount);
356
  return TRUE;
357
}
358
#endif
359
360
BOOL freerdp_check_fds(freerdp* instance)
361
0
{
362
0
  int status = 0;
363
0
  rdpRdp* rdp = nullptr;
364
365
0
  if (!instance)
366
0
    return FALSE;
367
368
0
  if (!instance->context)
369
0
    return FALSE;
370
371
0
  if (!instance->context->rdp)
372
0
    return FALSE;
373
374
0
  rdp = instance->context->rdp;
375
0
  status = rdp_check_fds(rdp);
376
377
0
  if (status < 0)
378
0
  {
379
0
    TerminateEventArgs e;
380
0
    rdpContext* context = instance->context;
381
0
    WINPR_ASSERT(context);
382
383
0
    WLog_Print(context->log, WLOG_DEBUG, "rdp_check_fds() - %i", status);
384
0
    EventArgsInit(&e, "freerdp");
385
0
    e.code = 0;
386
0
    if (PubSub_OnTerminate(rdp->pubSub, context, &e) < 0)
387
0
      return FALSE;
388
0
    return FALSE;
389
0
  }
390
391
0
  return TRUE;
392
0
}
393
394
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count)
395
0
{
396
0
  DWORD nCount = 0;
397
398
0
  WINPR_ASSERT(context);
399
0
  WINPR_ASSERT(context->rdp);
400
0
  WINPR_ASSERT(events || (count == 0));
401
402
0
  const size_t rrc = rdp_get_event_handles(context->rdp, &events[nCount], count - nCount);
403
0
  if (rrc == 0)
404
0
    return 0;
405
406
0
  nCount += WINPR_ASSERTING_INT_CAST(uint32_t, rrc);
407
408
0
  if (events && (nCount < count + 2))
409
0
  {
410
0
    events[nCount++] = freerdp_channels_get_event_handle(context->instance);
411
0
    events[nCount++] = getChannelErrorEventHandle(context);
412
0
  }
413
0
  else
414
0
    return 0;
415
416
0
  const SSIZE_T rc = freerdp_client_channel_get_registered_event_handles(
417
0
      context->channels, &events[nCount], count - nCount);
418
0
  if (rc < 0)
419
0
    return 0;
420
0
  return nCount + (DWORD)rc;
421
0
}
422
423
/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
424
static BOOL freerdp_prevent_session_lock(rdpContext* context)
425
0
{
426
0
  WINPR_ASSERT(context);
427
0
  WINPR_ASSERT(context->input);
428
429
0
  rdp_input_internal* in = input_cast(context->input);
430
431
0
  UINT32 FakeMouseMotionInterval =
432
0
      freerdp_settings_get_uint32(context->settings, FreeRDP_FakeMouseMotionInterval);
433
0
  if (FakeMouseMotionInterval && in->lastInputTimestamp)
434
0
  {
435
0
    const time_t now = time(nullptr);
436
0
    if (WINPR_ASSERTING_INT_CAST(size_t, now) - in->lastInputTimestamp >
437
0
        FakeMouseMotionInterval)
438
0
    {
439
0
      WLog_Print(context->log, WLOG_DEBUG,
440
0
                 "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
441
0
                 "FakeMouseMotionInterval=%" PRIu32,
442
0
                 in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
443
444
0
      BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
445
0
                                                   in->lastY);
446
0
      if (!status)
447
0
      {
448
0
        if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
449
0
          WLog_Print(context->log, WLOG_ERROR,
450
0
                     "freerdp_prevent_session_lock() failed - %" PRIi32 "", status);
451
452
0
        return FALSE;
453
0
      }
454
455
0
      return status;
456
0
    }
457
0
  }
458
459
0
  return TRUE;
460
0
}
461
462
BOOL freerdp_check_event_handles(rdpContext* context)
463
0
{
464
0
  WINPR_ASSERT(context);
465
466
0
  BOOL status = freerdp_check_fds(context->instance);
467
468
0
  if (!status)
469
0
  {
470
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
471
0
      WLog_Print(context->log, WLOG_ERROR, "freerdp_check_fds() failed - %" PRIi32 "",
472
0
                 status);
473
474
0
    return FALSE;
475
0
  }
476
477
0
  status = freerdp_channels_check_fds(context->channels, context->instance);
478
479
0
  if (!status)
480
0
  {
481
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
482
0
      WLog_Print(context->log, WLOG_ERROR,
483
0
                 "freerdp_channels_check_fds() failed - %" PRIi32 "", status);
484
485
0
    return FALSE;
486
0
  }
487
488
0
  status = checkChannelErrorEvent(context);
489
490
0
  if (!status)
491
0
  {
492
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
493
0
      WLog_Print(context->log, WLOG_ERROR, "checkChannelErrorEvent() failed - %" PRIi32 "",
494
0
                 status);
495
496
0
    return FALSE;
497
0
  }
498
499
0
  status = freerdp_prevent_session_lock(context);
500
501
0
  return status;
502
0
}
503
504
wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
505
0
{
506
0
  wMessageQueue* queue = nullptr;
507
508
0
  WINPR_ASSERT(instance);
509
510
0
  rdpContext* context = instance->context;
511
0
  WINPR_ASSERT(context);
512
513
0
  switch (id)
514
0
  {
515
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
516
0
    {
517
0
      rdp_update_internal* update = update_cast(context->update);
518
0
      queue = update->queue;
519
0
    }
520
0
    break;
521
522
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
523
0
    {
524
0
      rdp_input_internal* input = input_cast(context->input);
525
0
      queue = input->queue;
526
0
    }
527
0
    break;
528
0
    default:
529
0
      break;
530
0
  }
531
532
0
  return queue;
533
0
}
534
535
HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
536
0
{
537
0
  HANDLE event = nullptr;
538
0
  wMessageQueue* queue = freerdp_get_message_queue(instance, id);
539
540
0
  if (queue)
541
0
    event = MessageQueue_Event(queue);
542
543
0
  return event;
544
0
}
545
546
int freerdp_message_queue_process_message(freerdp* instance, DWORD id, wMessage* message)
547
0
{
548
0
  int status = -1;
549
0
  rdpContext* context = nullptr;
550
551
0
  WINPR_ASSERT(instance);
552
553
0
  context = instance->context;
554
0
  WINPR_ASSERT(context);
555
556
0
  switch (id)
557
0
  {
558
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
559
0
      status = update_message_queue_process_message(context->update, message);
560
0
      break;
561
562
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
563
0
      status = input_message_queue_process_message(context->input, message);
564
0
      break;
565
0
    default:
566
0
      break;
567
0
  }
568
569
0
  return status;
570
0
}
571
572
int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
573
0
{
574
0
  int status = -1;
575
0
  rdpContext* context = nullptr;
576
577
0
  WINPR_ASSERT(instance);
578
579
0
  context = instance->context;
580
0
  WINPR_ASSERT(context);
581
582
0
  switch (id)
583
0
  {
584
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
585
0
      status = update_message_queue_process_pending_messages(context->update);
586
0
      break;
587
588
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
589
0
      status = input_message_queue_process_pending_messages(context->input);
590
0
      break;
591
0
    default:
592
0
      break;
593
0
  }
594
595
0
  return status;
596
0
}
597
598
static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data,
599
                                      size_t size)
600
0
{
601
0
  WINPR_ASSERT(instance);
602
0
  WINPR_ASSERT(instance->context);
603
0
  WINPR_ASSERT(instance->context->rdp);
604
0
  return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
605
0
}
606
607
static BOOL freerdp_send_channel_packet(freerdp* instance, UINT16 channelId, size_t totalSize,
608
                                        UINT32 flags, const BYTE* data, size_t chunkSize)
609
0
{
610
0
  WINPR_ASSERT(instance);
611
0
  WINPR_ASSERT(instance->context);
612
0
  WINPR_ASSERT(instance->context->rdp);
613
0
  return rdp_channel_send_packet(instance->context->rdp, channelId, totalSize, flags, data,
614
0
                                 chunkSize);
615
0
}
616
617
BOOL freerdp_disconnect(freerdp* instance)
618
0
{
619
0
  BOOL rc = TRUE;
620
621
0
  if (!instance || !instance->context)
622
0
    return FALSE;
623
624
0
  rdpRdp* rdp = instance->context->rdp;
625
0
  if (rdp)
626
0
  {
627
    /* Try to send a [MS-RDPBCGR] 1.3.1.4.1 User-Initiated on Client PDU, we don't care about
628
     * success */
629
0
    if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
630
0
    {
631
0
      (void)mcs_send_disconnect_provider_ultimatum(rdp->mcs,
632
0
                                                   Disconnect_Ultimatum_user_requested);
633
0
    }
634
0
  }
635
636
0
  utils_abort_connect(rdp);
637
638
0
  if (!rdp_client_disconnect(rdp))
639
0
    rc = FALSE;
640
641
0
  rdp_update_internal* up = nullptr;
642
0
  if (rdp && rdp->update)
643
0
  {
644
0
    up = update_cast(rdp->update);
645
646
0
    update_post_disconnect(rdp->update);
647
0
  }
648
649
0
  IFCALL(instance->PostDisconnect, instance);
650
0
  cache_free(instance->context->cache);
651
0
  instance->context->cache = nullptr;
652
653
0
  if (up)
654
0
  {
655
0
    update_dump_stats(rdp->update);
656
0
    if (up->pcap_rfx)
657
0
    {
658
0
      up->dump_rfx = FALSE;
659
0
      pcap_close(up->pcap_rfx);
660
0
      up->pcap_rfx = nullptr;
661
0
    }
662
0
  }
663
664
0
  if (instance->context->channels)
665
0
    freerdp_channels_close(instance->context->channels, instance);
666
667
0
  IFCALL(instance->PostFinalDisconnect, instance);
668
669
0
  freerdp_del_signal_cleanup_handler(instance->context, sig_abort_connect);
670
0
  return rc;
671
0
}
672
673
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
674
BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
675
0
{
676
0
  WINPR_ASSERT(instance);
677
0
  return freerdp_disconnect_before_reconnect_context(instance->context);
678
0
}
679
#endif
680
681
BOOL freerdp_disconnect_before_reconnect_context(rdpContext* context)
682
0
{
683
0
  rdpRdp* rdp = nullptr;
684
685
0
  WINPR_ASSERT(context);
686
687
0
  rdp = context->rdp;
688
0
  return rdp_client_disconnect_and_clear(rdp);
689
0
}
690
691
BOOL freerdp_reconnect(freerdp* instance)
692
0
{
693
0
  rdpRdp* rdp = nullptr;
694
695
0
  WINPR_ASSERT(instance);
696
0
  WINPR_ASSERT(instance->context);
697
698
0
  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
699
0
    return FALSE;
700
701
0
  rdp = instance->context->rdp;
702
703
0
  if (!utils_reset_abort(instance->context->rdp))
704
0
    return FALSE;
705
0
  return rdp_client_reconnect(rdp);
706
0
}
707
708
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
709
BOOL freerdp_shall_disconnect(const freerdp* instance)
710
0
{
711
0
  if (!instance)
712
0
    return FALSE;
713
714
0
  return freerdp_shall_disconnect_context(instance->context);
715
0
}
716
#endif
717
718
BOOL freerdp_shall_disconnect_context(const rdpContext* context)
719
26
{
720
26
  if (!context)
721
0
    return FALSE;
722
723
26
  return utils_abort_event_is_set(context->rdp);
724
26
}
725
726
BOOL freerdp_focus_required(freerdp* instance)
727
0
{
728
0
  rdpRdp* rdp = nullptr;
729
0
  BOOL bRetCode = FALSE;
730
731
0
  WINPR_ASSERT(instance);
732
0
  WINPR_ASSERT(instance->context);
733
734
0
  rdp = instance->context->rdp;
735
0
  WINPR_ASSERT(rdp);
736
737
0
  if (rdp->resendFocus)
738
0
  {
739
0
    bRetCode = TRUE;
740
0
    rdp->resendFocus = FALSE;
741
0
  }
742
743
0
  return bRetCode;
744
0
}
745
746
void freerdp_set_focus(freerdp* instance)
747
0
{
748
0
  rdpRdp* rdp = nullptr;
749
750
0
  WINPR_ASSERT(instance);
751
0
  WINPR_ASSERT(instance->context);
752
753
0
  rdp = instance->context->rdp;
754
0
  WINPR_ASSERT(rdp);
755
756
0
  rdp->resendFocus = TRUE;
757
0
}
758
759
void freerdp_get_version(int* major, int* minor, int* revision)
760
0
{
761
0
  if (major != nullptr)
762
0
    *major = FREERDP_VERSION_MAJOR;
763
764
0
  if (minor != nullptr)
765
0
    *minor = FREERDP_VERSION_MINOR;
766
767
0
  if (revision != nullptr)
768
0
    *revision = FREERDP_VERSION_REVISION;
769
0
}
770
771
const char* freerdp_get_version_string(void)
772
0
{
773
0
  return FREERDP_VERSION_FULL;
774
0
}
775
776
const char* freerdp_get_build_config(void)
777
0
{
778
0
  WINPR_PRAGMA_DIAG_PUSH
779
0
  WINPR_PRAGMA_DIAG_IGNORED_OVERLENGTH_STRINGS
780
0
  static const char build_config[] =
781
0
      "Build configuration: " FREERDP_BUILD_CONFIG "\n"
782
0
      "Build type:          " FREERDP_BUILD_TYPE "\n"
783
0
      "CFLAGS:              " FREERDP_CFLAGS "\n"
784
0
      "Compiler:            " FREERDP_COMPILER_ID ", " FREERDP_COMPILER_VERSION "\n"
785
0
      "Target architecture: " FREERDP_TARGET_ARCH "\n";
786
0
  WINPR_PRAGMA_DIAG_POP
787
0
  return build_config;
788
0
}
789
790
const char* freerdp_get_build_revision(void)
791
0
{
792
0
  return FREERDP_GIT_REVISION;
793
0
}
794
795
static wEventType FreeRDP_Events[] = {
796
  DEFINE_EVENT_ENTRY(WindowStateChange),   DEFINE_EVENT_ENTRY(ResizeWindow),
797
  DEFINE_EVENT_ENTRY(LocalResizeWindow),   DEFINE_EVENT_ENTRY(EmbedWindow),
798
  DEFINE_EVENT_ENTRY(PanningChange),       DEFINE_EVENT_ENTRY(ZoomingChange),
799
  DEFINE_EVENT_ENTRY(ErrorInfo),           DEFINE_EVENT_ENTRY(Terminate),
800
  DEFINE_EVENT_ENTRY(ConnectionResult),    DEFINE_EVENT_ENTRY(ChannelConnected),
801
  DEFINE_EVENT_ENTRY(ChannelDisconnected), DEFINE_EVENT_ENTRY(MouseEvent),
802
  DEFINE_EVENT_ENTRY(Activated),           DEFINE_EVENT_ENTRY(Timer),
803
  DEFINE_EVENT_ENTRY(GraphicsReset),       DEFINE_EVENT_ENTRY(UserNotification),
804
  DEFINE_EVENT_ENTRY(ChannelInitialized),  DEFINE_EVENT_ENTRY(ChannelTerminated),
805
  DEFINE_EVENT_ENTRY(StateChanged)
806
};
807
808
/** Allocator function for a rdp context.
809
 *  The function will allocate a rdpRdp structure using rdp_new(), then copy
810
 *  its contents to the appropriate fields in the rdp_freerdp structure given in parameters.
811
 *  It will also initialize the 'context' field in the rdp_freerdp structure as needed.
812
 *  If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at
813
 * the end of the function.
814
 *
815
 *  @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new
816
 * context.
817
 */
818
BOOL freerdp_context_new(freerdp* instance)
819
0
{
820
0
  return freerdp_context_new_ex(instance, nullptr);
821
0
}
822
823
static BOOL freerdp_common_context(rdpContext* context, AccessTokenType tokenType, char** token,
824
                                   size_t count, ...)
825
0
{
826
0
  BOOL rc = FALSE;
827
828
0
  WINPR_ASSERT(context);
829
0
  if (!context->instance || !context->instance->GetAccessToken)
830
0
    return TRUE;
831
832
0
  va_list ap = WINPR_C_ARRAY_INIT;
833
0
  va_start(ap, count);
834
0
  switch (tokenType)
835
0
  {
836
0
    case ACCESS_TOKEN_TYPE_AAD:
837
0
      if (count != 2)
838
0
      {
839
0
        WLog_ERR(TAG,
840
0
                 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
841
0
                 ", aborting",
842
0
                 count);
843
0
      }
844
0
      else
845
0
      {
846
0
        const char* scope = va_arg(ap, const char*);
847
0
        const char* req_cnf = va_arg(ap, const char*);
848
0
        rc = context->instance->GetAccessToken(context->instance, tokenType, token, count,
849
0
                                               scope, req_cnf);
850
0
      }
851
0
      break;
852
0
    case ACCESS_TOKEN_TYPE_AVD:
853
0
      if (count != 0)
854
0
      {
855
0
        WLog_WARN(TAG,
856
0
                  "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
857
0
                  ", ignoring",
858
0
                  count);
859
0
      }
860
0
      else
861
0
      {
862
0
        rc = context->instance->GetAccessToken(context->instance, tokenType, token, count);
863
0
      }
864
0
      break;
865
0
    default:
866
0
      break;
867
0
  }
868
0
  va_end(ap);
869
870
0
  if (!rc)
871
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
872
873
0
  return rc;
874
0
}
875
876
BOOL freerdp_context_new_ex(freerdp* instance, rdpSettings* settings)
877
14.3k
{
878
14.3k
  rdpRdp* rdp = nullptr;
879
14.3k
  rdpContext* context = nullptr;
880
14.3k
  BOOL ret = TRUE;
881
882
14.3k
  WINPR_ASSERT(instance);
883
884
14.3k
  instance->context = context = (rdpContext*)calloc(1, instance->ContextSize);
885
886
14.3k
  if (!context)
887
0
    return FALSE;
888
889
14.3k
  context->log = WLog_Get(TAG);
890
14.3k
  if (!context->log)
891
0
    goto fail;
892
893
  /* Set to external settings, prevents rdp_new from creating its own instance */
894
14.3k
  context->settings = settings;
895
14.3k
  context->instance = instance;
896
14.3k
  context->ServerMode = FALSE;
897
14.3k
  context->disconnectUltimatum = 0;
898
899
14.3k
  context->metrics = metrics_new(context);
900
901
14.3k
  if (!context->metrics)
902
0
    goto fail;
903
904
14.3k
  rdp = rdp_new(context);
905
906
14.3k
  if (!rdp)
907
0
    goto fail;
908
909
14.3k
  context->rdp = rdp;
910
14.3k
  context->pubSub = rdp->pubSub;
911
912
14.3k
  if (!context->pubSub)
913
0
    goto fail;
914
915
14.3k
  PubSub_AddEventTypes(rdp->pubSub, FreeRDP_Events, ARRAYSIZE(FreeRDP_Events));
916
917
#if defined(WITH_FREERDP_DEPRECATED)
918
  instance->input = rdp->input;
919
  instance->update = rdp->update;
920
  instance->settings = rdp->settings;
921
  instance->autodetect = rdp->autodetect;
922
#endif
923
924
14.3k
  instance->heartbeat = rdp->heartbeat;
925
14.3k
  context->graphics = graphics_new(context);
926
927
14.3k
  if (!context->graphics)
928
0
    goto fail;
929
930
14.3k
  context->input = rdp->input;
931
14.3k
  context->update = rdp->update;
932
14.3k
  context->settings = rdp->settings;
933
14.3k
  context->autodetect = rdp->autodetect;
934
935
14.3k
  if (!(context->errorDescription = calloc(1, 500)))
936
0
  {
937
0
    WLog_Print(context->log, WLOG_ERROR, "calloc failed!");
938
0
    goto fail;
939
0
  }
940
941
14.3k
  if (!(context->channelErrorEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
942
0
  {
943
0
    WLog_Print(context->log, WLOG_ERROR, "CreateEvent failed!");
944
0
    goto fail;
945
0
  }
946
947
14.3k
  update_register_client_callbacks(rdp->update);
948
949
14.3k
  if (!(context->channels = freerdp_channels_new(instance)))
950
0
    goto fail;
951
952
14.3k
  context->dump = stream_dump_new();
953
14.3k
  if (!context->dump)
954
0
    goto fail;
955
956
  /* Fallback:
957
   * Client common library might set a function pointer to handle this, but here we provide a
958
   * default implementation that simply calls instance->GetAccessToken.
959
   */
960
14.3k
  if (!freerdp_set_common_access_token(context, freerdp_common_context))
961
0
    goto fail;
962
963
14.3k
  IFCALLRET(instance->ContextNew, ret, instance, context);
964
965
14.3k
  if (!ret)
966
0
    goto fail;
967
968
14.3k
  return TRUE;
969
970
0
fail:
971
0
  freerdp_context_free(instance);
972
0
  return FALSE;
973
14.3k
}
974
975
BOOL freerdp_context_reset(freerdp* instance)
976
0
{
977
0
  if (!instance)
978
0
    return FALSE;
979
980
0
  WINPR_ASSERT(instance->context);
981
0
  rdpRdp* rdp = instance->context->rdp;
982
983
0
  return rdp_reset_runtime_settings(rdp);
984
0
}
985
986
/** Deallocator function for a rdp context.
987
 *  The function will deallocate the resources from the 'instance' parameter that were allocated
988
 * from a call to freerdp_context_new(). If the ContextFree callback is set in the 'instance'
989
 * parameter, it will be called before deallocation occurs.
990
 *
991
 *  @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to
992
 * freerdp_context_new(). On return, the fields associated to the context are invalid.
993
 */
994
void freerdp_context_free(freerdp* instance)
995
14.3k
{
996
14.3k
  rdpContext* ctx = nullptr;
997
998
14.3k
  if (!instance)
999
0
    return;
1000
1001
14.3k
  if (!instance->context)
1002
0
    return;
1003
1004
14.3k
  ctx = instance->context;
1005
1006
14.3k
  IFCALL(instance->ContextFree, instance, ctx);
1007
14.3k
  rdp_free(ctx->rdp);
1008
14.3k
  ctx->rdp = nullptr;
1009
14.3k
  ctx->settings = nullptr; /* owned by rdpRdp */
1010
1011
14.3k
  graphics_free(ctx->graphics);
1012
14.3k
  ctx->graphics = nullptr;
1013
1014
14.3k
  metrics_free(ctx->metrics);
1015
14.3k
  ctx->metrics = nullptr;
1016
1017
14.3k
  if (ctx->channelErrorEvent)
1018
14.3k
    (void)CloseHandle(ctx->channelErrorEvent);
1019
14.3k
  ctx->channelErrorEvent = nullptr;
1020
1021
14.3k
  free(ctx->errorDescription);
1022
14.3k
  ctx->errorDescription = nullptr;
1023
1024
14.3k
  freerdp_channels_free(ctx->channels);
1025
14.3k
  ctx->channels = nullptr;
1026
1027
14.3k
  freerdp_client_codecs_free(ctx->codecs);
1028
14.3k
  ctx->codecs = nullptr;
1029
1030
14.3k
  stream_dump_free(ctx->dump);
1031
14.3k
  ctx->dump = nullptr;
1032
1033
14.3k
  ctx->input = nullptr;      /* owned by rdpRdp */
1034
14.3k
  ctx->update = nullptr;     /* owned by rdpRdp */
1035
14.3k
  ctx->settings = nullptr;   /* owned by rdpRdp */
1036
14.3k
  ctx->autodetect = nullptr; /* owned by rdpRdp */
1037
1038
14.3k
  free(ctx);
1039
14.3k
  instance->context = nullptr;
1040
#if defined(WITH_FREERDP_DEPRECATED)
1041
  instance->input = nullptr;      /* owned by rdpRdp */
1042
  instance->update = nullptr;     /* owned by rdpRdp */
1043
  instance->settings = nullptr;   /* owned by rdpRdp */
1044
  instance->autodetect = nullptr; /* owned by rdpRdp */
1045
#endif
1046
14.3k
  instance->heartbeat = nullptr; /* owned by rdpRdp */
1047
14.3k
}
1048
1049
int freerdp_get_disconnect_ultimatum(const rdpContext* context)
1050
0
{
1051
0
  WINPR_ASSERT(context);
1052
0
  return context->disconnectUltimatum;
1053
0
}
1054
1055
UINT32 freerdp_error_info(const freerdp* instance)
1056
0
{
1057
0
  WINPR_ASSERT(instance);
1058
0
  WINPR_ASSERT(instance->context);
1059
0
  WINPR_ASSERT(instance->context->rdp);
1060
0
  return instance->context->rdp->errorInfo;
1061
0
}
1062
1063
void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
1064
0
{
1065
0
  if (!rdp)
1066
0
    return;
1067
1068
0
  rdp_set_error_info(rdp, error);
1069
0
}
1070
1071
BOOL freerdp_send_error_info(rdpRdp* rdp)
1072
0
{
1073
0
  if (!rdp)
1074
0
    return FALSE;
1075
1076
0
  return rdp_send_error_info(rdp);
1077
0
}
1078
1079
UINT32 freerdp_get_last_error(const rdpContext* context)
1080
71
{
1081
71
  WINPR_ASSERT(context);
1082
71
  return context->LastError;
1083
71
}
1084
1085
const char* freerdp_get_last_error_name(UINT32 code)
1086
1.10k
{
1087
1.10k
  const char* name = nullptr;
1088
1.10k
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1089
1.10k
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1090
1091
1.10k
  switch (cls)
1092
1.10k
  {
1093
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1094
0
      name = freerdp_get_error_base_name(type);
1095
0
      break;
1096
1097
726
    case FREERDP_ERROR_ERRINFO_CLASS:
1098
726
      name = freerdp_get_error_info_name(type);
1099
726
      break;
1100
1101
282
    case FREERDP_ERROR_CONNECT_CLASS:
1102
282
      name = freerdp_get_error_connect_name(type);
1103
282
      break;
1104
1105
101
    default:
1106
101
      name = rpc_error_to_string(code);
1107
101
      break;
1108
1.10k
  }
1109
1110
1.10k
  return name;
1111
1.10k
}
1112
1113
const char* freerdp_get_last_error_string(UINT32 code)
1114
0
{
1115
0
  const char* string = nullptr;
1116
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1117
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1118
1119
0
  switch (cls)
1120
0
  {
1121
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1122
0
      string = freerdp_get_error_base_string(type);
1123
0
      break;
1124
1125
0
    case FREERDP_ERROR_ERRINFO_CLASS:
1126
0
      string = freerdp_get_error_info_string(type);
1127
0
      break;
1128
1129
0
    case FREERDP_ERROR_CONNECT_CLASS:
1130
0
      string = freerdp_get_error_connect_string(type);
1131
0
      break;
1132
1133
0
    default:
1134
0
      string = rpc_error_to_string(code);
1135
0
      break;
1136
0
  }
1137
1138
0
  return string;
1139
0
}
1140
1141
const char* freerdp_get_last_error_category(UINT32 code)
1142
0
{
1143
0
  const char* string = nullptr;
1144
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1145
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1146
1147
0
  switch (cls)
1148
0
  {
1149
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1150
0
      string = freerdp_get_error_base_category(type);
1151
0
      break;
1152
1153
0
    case FREERDP_ERROR_ERRINFO_CLASS:
1154
0
      string = freerdp_get_error_info_category(type);
1155
0
      break;
1156
1157
0
    case FREERDP_ERROR_CONNECT_CLASS:
1158
0
      string = freerdp_get_error_connect_category(type);
1159
0
      break;
1160
1161
0
    default:
1162
0
      string = rpc_error_to_category(code);
1163
0
      break;
1164
0
  }
1165
1166
0
  return string;
1167
0
}
1168
1169
void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char* fkt,
1170
                               const char* file, int line)
1171
1.01k
{
1172
1.01k
  WINPR_ASSERT(context);
1173
1.01k
  WINPR_ASSERT(line >= 0);
1174
1175
1.01k
  if (lastError)
1176
1.01k
  {
1177
1.01k
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1178
1.01k
    {
1179
1.01k
      WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1180
1.01k
                            "%s [0x%08" PRIX32 "]", freerdp_get_last_error_name(lastError),
1181
1.01k
                            lastError);
1182
1.01k
    }
1183
1.01k
  }
1184
1185
1.01k
  if (lastError == FREERDP_ERROR_SUCCESS)
1186
5
  {
1187
5
    if (WLog_IsLevelActive(context->log, WLOG_DEBUG))
1188
0
      WLog_PrintTextMessage(context->log, WLOG_DEBUG, (size_t)line, file, fkt,
1189
0
                            "resetting error state");
1190
5
  }
1191
1.01k
  else if (context->LastError != FREERDP_ERROR_SUCCESS)
1192
48
  {
1193
48
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1194
48
    {
1195
48
      WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1196
48
                            "TODO: Trying to set error code %s, but %s already set!",
1197
48
                            freerdp_get_last_error_name(lastError),
1198
48
                            freerdp_get_last_error_name(context->LastError));
1199
48
    }
1200
48
  }
1201
1.01k
  context->LastError = lastError;
1202
1.01k
}
1203
1204
const char* freerdp_get_logon_error_info_type_ex(UINT32 type, char* buffer, size_t size)
1205
0
{
1206
0
  const char* str = freerdp_get_logon_error_info_type(type);
1207
0
  (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, type);
1208
0
  return buffer;
1209
0
}
1210
1211
const char* freerdp_get_logon_error_info_type(UINT32 type)
1212
106
{
1213
106
#define CASE_ENTRY(x) \
1214
106
  case x:           \
1215
4
    return #x
1216
106
  switch (type)
1217
106
  {
1218
0
    CASE_ENTRY(LOGON_MSG_SESSION_BUSY_OPTIONS);
1219
0
    CASE_ENTRY(LOGON_MSG_DISCONNECT_REFUSED);
1220
0
    CASE_ENTRY(LOGON_MSG_NO_PERMISSION);
1221
0
    CASE_ENTRY(LOGON_MSG_BUMP_OPTIONS);
1222
0
    CASE_ENTRY(LOGON_MSG_RECONNECT_OPTIONS);
1223
0
    CASE_ENTRY(LOGON_MSG_SESSION_TERMINATE);
1224
0
    CASE_ENTRY(LOGON_MSG_SESSION_CONTINUE);
1225
4
    CASE_ENTRY(ERROR_CODE_ACCESS_DENIED);
1226
1227
102
    default:
1228
102
      return "UNKNOWN";
1229
106
  }
1230
106
#undef CASE_ENTRY
1231
106
}
1232
1233
const char* freerdp_get_logon_error_info_data(UINT32 data)
1234
106
{
1235
106
  switch (data)
1236
106
  {
1237
5
    case LOGON_FAILED_BAD_PASSWORD:
1238
5
      return "LOGON_FAILED_BAD_PASSWORD";
1239
1240
2
    case LOGON_FAILED_UPDATE_PASSWORD:
1241
2
      return "LOGON_FAILED_UPDATE_PASSWORD";
1242
1243
0
    case LOGON_FAILED_OTHER:
1244
0
      return "LOGON_FAILED_OTHER";
1245
1246
0
    case LOGON_WARNING:
1247
0
      return "LOGON_WARNING";
1248
1249
99
    default:
1250
99
      return "SESSION_ID";
1251
106
  }
1252
106
}
1253
1254
const char* freerdp_get_logon_error_info_data_ex(UINT32 data, char* buffer, size_t size)
1255
0
{
1256
0
  const char* str = freerdp_get_logon_error_info_data(data);
1257
0
  (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, data);
1258
0
  return buffer;
1259
0
}
1260
1261
/** Allocator function for the rdp_freerdp structure.
1262
 *  @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
1263
 */
1264
freerdp* freerdp_new(void)
1265
14.3k
{
1266
14.3k
  if (!utils_set_umask())
1267
0
    return nullptr;
1268
1269
14.3k
  freerdp* instance = (freerdp*)calloc(1, sizeof(freerdp));
1270
1271
14.3k
  if (!instance)
1272
0
    return nullptr;
1273
1274
14.3k
  instance->ContextSize = sizeof(rdpContext);
1275
14.3k
  instance->SendChannelData = freerdp_send_channel_data;
1276
14.3k
  instance->SendChannelPacket = freerdp_send_channel_packet;
1277
14.3k
  instance->ReceiveChannelData = freerdp_channels_data;
1278
14.3k
  return instance;
1279
14.3k
}
1280
1281
/** Deallocator function for the rdp_freerdp structure.
1282
 *  @param instance - pointer to the rdp_freerdp structure to deallocate.
1283
 *                    On return, this pointer is not valid anymore.
1284
 */
1285
void freerdp_free(freerdp* instance)
1286
14.3k
{
1287
14.3k
  free(instance);
1288
14.3k
}
1289
1290
ULONG freerdp_get_transport_sent(const rdpContext* context, BOOL resetCount)
1291
0
{
1292
0
  WINPR_ASSERT(context);
1293
0
  WINPR_ASSERT(context->rdp);
1294
0
  UINT64 rc = transport_get_bytes_sent(context->rdp->transport, resetCount);
1295
0
  return WINPR_CXX_COMPAT_CAST(ULONG, MIN(rc, UINT32_MAX));
1296
0
}
1297
1298
BOOL freerdp_nla_impersonate(rdpContext* context)
1299
0
{
1300
0
  rdpNla* nla = nullptr;
1301
1302
0
  if (!context)
1303
0
    return FALSE;
1304
1305
0
  if (!context->rdp)
1306
0
    return FALSE;
1307
1308
0
  if (!context->rdp->transport)
1309
0
    return FALSE;
1310
1311
0
  nla = transport_get_nla(context->rdp->transport);
1312
0
  return nla_impersonate(nla);
1313
0
}
1314
1315
BOOL freerdp_nla_revert_to_self(rdpContext* context)
1316
0
{
1317
0
  rdpNla* nla = nullptr;
1318
1319
0
  if (!context)
1320
0
    return FALSE;
1321
1322
0
  if (!context->rdp)
1323
0
    return FALSE;
1324
1325
0
  if (!context->rdp->transport)
1326
0
    return FALSE;
1327
1328
0
  nla = transport_get_nla(context->rdp->transport);
1329
0
  return nla_revert_to_self(nla);
1330
0
}
1331
1332
UINT32 freerdp_get_nla_sspi_error(const rdpContext* context)
1333
0
{
1334
0
  WINPR_ASSERT(context);
1335
0
  WINPR_ASSERT(context->rdp);
1336
0
  WINPR_ASSERT(context->rdp->transport);
1337
1338
0
  rdpNla* nla = context->rdp->nla;
1339
0
  if (!nla)
1340
0
    nla = transport_get_nla(context->rdp->transport);
1341
0
  return (UINT32)nla_get_sspi_error(nla);
1342
0
}
1343
1344
BOOL freerdp_nla_encrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1345
0
{
1346
0
  WINPR_ASSERT(context);
1347
0
  WINPR_ASSERT(context->rdp);
1348
1349
0
  rdpNla* nla = context->rdp->nla;
1350
0
  return nla_encrypt(nla, inBuffer, outBuffer);
1351
0
}
1352
1353
BOOL freerdp_nla_decrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1354
0
{
1355
0
  WINPR_ASSERT(context);
1356
0
  WINPR_ASSERT(context->rdp);
1357
1358
0
  rdpNla* nla = context->rdp->nla;
1359
0
  return nla_decrypt(nla, inBuffer, outBuffer);
1360
0
}
1361
1362
SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ulAttr, PVOID pBuffer)
1363
0
{
1364
0
  WINPR_ASSERT(context);
1365
0
  WINPR_ASSERT(context->rdp);
1366
1367
0
  rdpNla* nla = context->rdp->nla;
1368
0
  if (!nla)
1369
0
    nla = transport_get_nla(context->rdp->transport);
1370
1371
0
  WINPR_ASSERT(nla);
1372
1373
0
  return nla_QueryContextAttributes(nla, ulAttr, pBuffer);
1374
0
}
1375
1376
SECURITY_STATUS freerdp_nla_FreeContextBuffer(rdpContext* context, PVOID pBuffer)
1377
0
{
1378
0
  WINPR_ASSERT(context);
1379
0
  WINPR_ASSERT(context->rdp);
1380
1381
0
  rdpNla* nla = context->rdp->nla;
1382
0
  if (!nla)
1383
0
    nla = transport_get_nla(context->rdp->transport);
1384
1385
0
  WINPR_ASSERT(nla);
1386
1387
0
  return nla_FreeContextBuffer(nla, pBuffer);
1388
0
}
1389
1390
HANDLE getChannelErrorEventHandle(rdpContext* context)
1391
0
{
1392
0
  WINPR_ASSERT(context);
1393
0
  return context->channelErrorEvent;
1394
0
}
1395
1396
BOOL checkChannelErrorEvent(rdpContext* context)
1397
0
{
1398
0
  WINPR_ASSERT(context);
1399
1400
0
  if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
1401
0
  {
1402
0
    WLog_Print(context->log, WLOG_ERROR, "%s. Error was %" PRIu32 "", context->errorDescription,
1403
0
               context->channelErrorNum);
1404
0
    return FALSE;
1405
0
  }
1406
1407
0
  return TRUE;
1408
0
}
1409
1410
/**
1411
 * Function description
1412
 *
1413
 * @return 0 on success, otherwise a Win32 error code
1414
 */
1415
UINT getChannelError(const rdpContext* context)
1416
0
{
1417
0
  WINPR_ASSERT(context);
1418
0
  return context->channelErrorNum;
1419
0
}
1420
1421
const char* getChannelErrorDescription(const rdpContext* context)
1422
0
{
1423
0
  WINPR_ASSERT(context);
1424
0
  return context->errorDescription;
1425
0
}
1426
1427
void clearChannelError(rdpContext* context)
1428
0
{
1429
0
  WINPR_ASSERT(context);
1430
0
  context->channelErrorNum = 0;
1431
0
  memset(context->errorDescription, 0, 500);
1432
0
  (void)ResetEvent(context->channelErrorEvent);
1433
0
}
1434
1435
WINPR_ATTR_FORMAT_ARG(3, 4)
1436
void setChannelError(rdpContext* context, UINT errorNum, WINPR_FORMAT_ARG const char* format, ...)
1437
21.5k
{
1438
21.5k
  va_list ap = WINPR_C_ARRAY_INIT;
1439
21.5k
  va_start(ap, format);
1440
1441
21.5k
  WINPR_ASSERT(context);
1442
1443
21.5k
  context->channelErrorNum = errorNum;
1444
21.5k
  (void)vsnprintf(context->errorDescription, 499, format, ap);
1445
21.5k
  va_end(ap);
1446
21.5k
  (void)SetEvent(context->channelErrorEvent);
1447
21.5k
}
1448
1449
const char* freerdp_nego_get_routing_token(const rdpContext* context, DWORD* length)
1450
0
{
1451
0
  if (!context || !context->rdp)
1452
0
    return nullptr;
1453
1454
0
  return (const char*)nego_get_routing_token(context->rdp->nego, length);
1455
0
}
1456
1457
BOOL freerdp_io_callback_set_event(rdpContext* context, BOOL set)
1458
0
{
1459
0
  WINPR_ASSERT(context);
1460
0
  return rdp_io_callback_set_event(context->rdp, set);
1461
0
}
1462
1463
const rdpTransportIo* freerdp_get_io_callbacks(rdpContext* context)
1464
0
{
1465
0
  WINPR_ASSERT(context);
1466
0
  return rdp_get_io_callbacks(context->rdp);
1467
0
}
1468
1469
BOOL freerdp_set_io_callbacks(rdpContext* context, const rdpTransportIo* io_callbacks)
1470
0
{
1471
0
  WINPR_ASSERT(context);
1472
0
  return rdp_set_io_callbacks(context->rdp, io_callbacks);
1473
0
}
1474
1475
BOOL freerdp_set_io_callback_context(rdpContext* context, void* usercontext)
1476
0
{
1477
0
  WINPR_ASSERT(context);
1478
0
  return rdp_set_io_callback_context(context->rdp, usercontext);
1479
0
}
1480
1481
void* freerdp_get_io_callback_context(rdpContext* context)
1482
0
{
1483
0
  WINPR_ASSERT(context);
1484
0
  return rdp_get_io_callback_context(context->rdp);
1485
0
}
1486
1487
CONNECTION_STATE freerdp_get_state(const rdpContext* context)
1488
0
{
1489
0
  WINPR_ASSERT(context);
1490
0
  return rdp_get_state(context->rdp);
1491
0
}
1492
1493
const char* freerdp_state_string(CONNECTION_STATE state)
1494
0
{
1495
0
  return rdp_state_string(state);
1496
0
}
1497
1498
BOOL freerdp_is_active_state(const rdpContext* context)
1499
0
{
1500
0
  WINPR_ASSERT(context);
1501
0
  return rdp_is_active_state(context->rdp);
1502
0
}
1503
1504
BOOL freerdp_channels_from_mcs(rdpSettings* settings, const rdpContext* context)
1505
0
{
1506
0
  WINPR_ASSERT(context);
1507
0
  return rdp_channels_from_mcs(settings, context->rdp);
1508
0
}
1509
1510
HANDLE freerdp_abort_event(rdpContext* context)
1511
0
{
1512
0
  WINPR_ASSERT(context);
1513
0
  return utils_get_abort_event(context->rdp);
1514
0
}
1515
1516
static void test_mcs_free(rdpMcs* mcs)
1517
30.1k
{
1518
30.1k
  if (!mcs)
1519
0
    return;
1520
1521
30.1k
  if (mcs->context)
1522
30.1k
  {
1523
30.1k
    rdpSettings* settings = mcs->context->settings;
1524
30.1k
    freerdp_settings_free(settings);
1525
30.1k
  }
1526
30.1k
  free(mcs->context);
1527
1528
30.1k
  mcs_free(mcs);
1529
30.1k
}
1530
1531
static rdpMcs* test_mcs_new(void)
1532
30.1k
{
1533
30.1k
  rdpSettings* settings = freerdp_settings_new(0);
1534
30.1k
  rdpContext* context = calloc(1, sizeof(rdpContext));
1535
1536
30.1k
  if (!settings)
1537
0
    goto fail;
1538
30.1k
  if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))
1539
0
    goto fail;
1540
1541
30.1k
  if (!context)
1542
0
    goto fail;
1543
30.1k
  context->settings = settings;
1544
30.1k
  return mcs_new(context);
1545
1546
0
fail:
1547
0
  free(context);
1548
0
  freerdp_settings_free(settings);
1549
1550
0
  return nullptr;
1551
30.1k
}
1552
1553
BOOL freerdp_is_valid_mcs_create_request(const BYTE* data, size_t size)
1554
15.0k
{
1555
1556
15.0k
  wStream sbuffer = WINPR_C_ARRAY_INIT;
1557
15.0k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1558
1559
15.0k
  WINPR_ASSERT(data || (size == 0));
1560
15.0k
  WINPR_ASSERT(s);
1561
1562
15.0k
  rdpMcs* mcs = test_mcs_new();
1563
15.0k
  WINPR_ASSERT(mcs);
1564
1565
15.0k
  BOOL result = mcs_recv_connect_initial(mcs, s);
1566
15.0k
  test_mcs_free(mcs);
1567
15.0k
  return result;
1568
15.0k
}
1569
1570
BOOL freerdp_is_valid_mcs_create_response(const BYTE* data, size_t size)
1571
15.0k
{
1572
1573
15.0k
  wStream sbuffer = WINPR_C_ARRAY_INIT;
1574
15.0k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1575
1576
15.0k
  WINPR_ASSERT(data || (size == 0));
1577
15.0k
  WINPR_ASSERT(s);
1578
1579
15.0k
  rdpMcs* mcs = test_mcs_new();
1580
15.0k
  WINPR_ASSERT(mcs);
1581
1582
15.0k
  BOOL result = mcs_recv_connect_response(mcs, s);
1583
15.0k
  test_mcs_free(mcs);
1584
15.0k
  return result;
1585
15.0k
}
1586
1587
BOOL freerdp_persist_credentials(rdpContext* context)
1588
0
{
1589
0
  if (!context)
1590
0
    return FALSE;
1591
0
  WINPR_ASSERT(context->rdp);
1592
0
  return utils_persist_credentials(context->rdp->originalSettings, context->rdp->settings);
1593
0
}
1594
1595
const char* freerdp_disconnect_reason_string(int reason)
1596
0
{
1597
0
  switch (reason)
1598
0
  {
1599
0
    case Disconnect_Ultimatum_domain_disconnected:
1600
0
      return "rn-domain-disconnected";
1601
0
    case Disconnect_Ultimatum_provider_initiated:
1602
0
      return "rn-provider-initiated";
1603
0
    case Disconnect_Ultimatum_token_purged:
1604
0
      return "rn-token-purged";
1605
0
    case Disconnect_Ultimatum_user_requested:
1606
0
      return "rn-user-requested";
1607
0
    case Disconnect_Ultimatum_channel_purged:
1608
0
      return "rn-channel-purged";
1609
0
    default:
1610
0
      return "rn-unknown";
1611
0
  }
1612
0
}
1613
1614
BOOL freerdp_set_common_access_token(rdpContext* context,
1615
                                     pGetCommonAccessToken GetCommonAccessToken)
1616
14.3k
{
1617
14.3k
  WINPR_ASSERT(context);
1618
14.3k
  WINPR_ASSERT(context->rdp);
1619
14.3k
  context->rdp->GetCommonAccessToken = GetCommonAccessToken;
1620
14.3k
  return TRUE;
1621
14.3k
}
1622
1623
pGetCommonAccessToken freerdp_get_common_access_token(const rdpContext* context)
1624
0
{
1625
0
  WINPR_ASSERT(context);
1626
0
  WINPR_ASSERT(context->rdp);
1627
0
  return context->rdp->GetCommonAccessToken;
1628
0
}