Coverage Report

Created: 2026-01-09 06:49

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