Coverage Report

Created: 2026-05-30 06:46

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