FreeRDP
libfreerdp/core/gateway/rpc.c
1 /*
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * RPC over HTTP
4  *
5  * Copyright 2012 Fujitsu Technology Solutions GmbH
6  * Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
7  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/crt.h>
27 #include <winpr/assert.h>
28 #include <winpr/tchar.h>
29 #include <winpr/synch.h>
30 #include <winpr/dsparse.h>
31 #include <winpr/crypto.h>
32 
33 #include <freerdp/log.h>
34 
35 #ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
36 #include <valgrind/memcheck.h>
37 #endif
38 
39 #include "../proxy.h"
40 #include "http.h"
41 #include "../credssp_auth.h"
42 #include "ncacn_http.h"
43 #include "rpc_bind.h"
44 #include "rpc_fault.h"
45 #include "rpc_client.h"
46 
47 #include "rpc.h"
48 #include "rts.h"
49 
50 #define TAG FREERDP_TAG("core.gateway.rpc")
51 
52 static const char* PTYPE_STRINGS[] = { "PTYPE_REQUEST", "PTYPE_PING",
53  "PTYPE_RESPONSE", "PTYPE_FAULT",
54  "PTYPE_WORKING", "PTYPE_NOCALL",
55  "PTYPE_REJECT", "PTYPE_ACK",
56  "PTYPE_CL_CANCEL", "PTYPE_FACK",
57  "PTYPE_CANCEL_ACK", "PTYPE_BIND",
58  "PTYPE_BIND_ACK", "PTYPE_BIND_NAK",
59  "PTYPE_ALTER_CONTEXT", "PTYPE_ALTER_CONTEXT_RESP",
60  "PTYPE_RPC_AUTH_3", "PTYPE_SHUTDOWN",
61  "PTYPE_CO_CANCEL", "PTYPE_ORPHANED",
62  "PTYPE_RTS", "" };
63 
64 static const char* client_in_state_str(CLIENT_IN_CHANNEL_STATE state)
65 {
66  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
67  const char* str = "CLIENT_IN_CHANNEL_STATE_UNKNOWN";
68 
69  switch (state)
70  {
71  case CLIENT_IN_CHANNEL_STATE_INITIAL:
72  str = "CLIENT_IN_CHANNEL_STATE_INITIAL";
73  break;
74 
75  case CLIENT_IN_CHANNEL_STATE_CONNECTED:
76  str = "CLIENT_IN_CHANNEL_STATE_CONNECTED";
77  break;
78 
79  case CLIENT_IN_CHANNEL_STATE_SECURITY:
80  str = "CLIENT_IN_CHANNEL_STATE_SECURITY";
81  break;
82 
83  case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
84  str = "CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
85  break;
86 
87  case CLIENT_IN_CHANNEL_STATE_OPENED:
88  str = "CLIENT_IN_CHANNEL_STATE_OPENED";
89  break;
90 
91  case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
92  str = "CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
93  break;
94 
95  case CLIENT_IN_CHANNEL_STATE_FINAL:
96  str = "CLIENT_IN_CHANNEL_STATE_FINAL";
97  break;
98  default:
99  break;
100  }
101  return str;
102 }
103 
104 static const char* client_out_state_str(CLIENT_OUT_CHANNEL_STATE state)
105 {
106  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
107  const char* str = "CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
108 
109  switch (state)
110  {
111  case CLIENT_OUT_CHANNEL_STATE_INITIAL:
112  str = "CLIENT_OUT_CHANNEL_STATE_INITIAL";
113  break;
114 
115  case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
116  str = "CLIENT_OUT_CHANNEL_STATE_CONNECTED";
117  break;
118 
119  case CLIENT_OUT_CHANNEL_STATE_SECURITY:
120  str = "CLIENT_OUT_CHANNEL_STATE_SECURITY";
121  break;
122 
123  case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
124  str = "CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
125  break;
126 
127  case CLIENT_OUT_CHANNEL_STATE_OPENED:
128  str = "CLIENT_OUT_CHANNEL_STATE_OPENED";
129  break;
130 
131  case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
132  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
133  break;
134 
135  case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
136  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
137  break;
138 
139  case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
140  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
141  break;
142 
143  case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
144  str = "CLIENT_OUT_CHANNEL_STATE_RECYCLED";
145  break;
146 
147  case CLIENT_OUT_CHANNEL_STATE_FINAL:
148  str = "CLIENT_OUT_CHANNEL_STATE_FINAL";
149  break;
150  default:
151  break;
152  }
153  return str;
154 }
155 
156 const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state)
157 {
158  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
159  const char* str = "VIRTUAL_CONNECTION_STATE_UNKNOWN";
160 
161  switch (state)
162  {
163  case VIRTUAL_CONNECTION_STATE_INITIAL:
164  str = "VIRTUAL_CONNECTION_STATE_INITIAL";
165  break;
166 
167  case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
168  str = "VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
169  break;
170 
171  case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
172  str = "VIRTUAL_CONNECTION_STATE_WAIT_A3W";
173  break;
174 
175  case VIRTUAL_CONNECTION_STATE_WAIT_C2:
176  str = "VIRTUAL_CONNECTION_STATE_WAIT_C2";
177  break;
178 
179  case VIRTUAL_CONNECTION_STATE_OPENED:
180  str = "VIRTUAL_CONNECTION_STATE_OPENED";
181  break;
182 
183  case VIRTUAL_CONNECTION_STATE_FINAL:
184  str = "VIRTUAL_CONNECTION_STATE_FINAL";
185  break;
186  default:
187  break;
188  }
189  return str;
190 }
191 
192 /*
193  * [MS-RPCH]: Remote Procedure Call over HTTP Protocol Specification:
194  * http://msdn.microsoft.com/en-us/library/cc243950/
195  *
196  *
197  *
198  * Connection Establishment
199  *
200  * Client Outbound Proxy Inbound Proxy Server
201  * | | | |
202  * |-----------------IN Channel Request--------------->| |
203  * |---OUT Channel Request-->| |<-Legacy Server Response-|
204  * | |<--------------Legacy Server Response--------------|
205  * | | | |
206  * |---------CONN_A1-------->| | |
207  * |----------------------CONN_B1--------------------->| |
208  * | |----------------------CONN_A2--------------------->|
209  * | | | |
210  * |<--OUT Channel Response--| |---------CONN_B2-------->|
211  * |<--------CONN_A3---------| | |
212  * | |<---------------------CONN_C1----------------------|
213  * | | |<--------CONN_B3---------|
214  * |<--------CONN_C2---------| | |
215  * | | | |
216  *
217  */
218 
219 void rpc_pdu_header_print(wLog* log, const rpcconn_hdr_t* header)
220 {
221  WINPR_ASSERT(header);
222 
223  WLog_Print(log, WLOG_INFO, "rpc_vers: %" PRIu8 "", header->common.rpc_vers);
224  WLog_Print(log, WLOG_INFO, "rpc_vers_minor: %" PRIu8 "", header->common.rpc_vers_minor);
225 
226  if (header->common.ptype > PTYPE_RTS)
227  WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", "PTYPE_UNKNOWN", header->common.ptype);
228  else
229  WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", PTYPE_STRINGS[header->common.ptype],
230  header->common.ptype);
231 
232  WLog_Print(log, WLOG_INFO, "pfc_flags (0x%02" PRIX8 ") = {", header->common.pfc_flags);
233 
234  if (header->common.pfc_flags & PFC_FIRST_FRAG)
235  WLog_Print(log, WLOG_INFO, " PFC_FIRST_FRAG");
236 
237  if (header->common.pfc_flags & PFC_LAST_FRAG)
238  WLog_Print(log, WLOG_INFO, " PFC_LAST_FRAG");
239 
240  if (header->common.pfc_flags & PFC_PENDING_CANCEL)
241  WLog_Print(log, WLOG_INFO, " PFC_PENDING_CANCEL");
242 
243  if (header->common.pfc_flags & PFC_RESERVED_1)
244  WLog_Print(log, WLOG_INFO, " PFC_RESERVED_1");
245 
246  if (header->common.pfc_flags & PFC_CONC_MPX)
247  WLog_Print(log, WLOG_INFO, " PFC_CONC_MPX");
248 
249  if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
250  WLog_Print(log, WLOG_INFO, " PFC_DID_NOT_EXECUTE");
251 
252  if (header->common.pfc_flags & PFC_OBJECT_UUID)
253  WLog_Print(log, WLOG_INFO, " PFC_OBJECT_UUID");
254 
255  WLog_Print(log, WLOG_INFO, " }");
256  WLog_Print(log, WLOG_INFO,
257  "packed_drep[4]: %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 "",
258  header->common.packed_drep[0], header->common.packed_drep[1],
259  header->common.packed_drep[2], header->common.packed_drep[3]);
260  WLog_Print(log, WLOG_INFO, "frag_length: %" PRIu16 "", header->common.frag_length);
261  WLog_Print(log, WLOG_INFO, "auth_length: %" PRIu16 "", header->common.auth_length);
262  WLog_Print(log, WLOG_INFO, "call_id: %" PRIu32 "", header->common.call_id);
263 
264  if (header->common.ptype == PTYPE_RESPONSE)
265  {
266  WLog_Print(log, WLOG_INFO, "alloc_hint: %" PRIu32 "", header->response.alloc_hint);
267  WLog_Print(log, WLOG_INFO, "p_cont_id: %" PRIu16 "", header->response.p_cont_id);
268  WLog_Print(log, WLOG_INFO, "cancel_count: %" PRIu8 "", header->response.cancel_count);
269  WLog_Print(log, WLOG_INFO, "reserved: %" PRIu8 "", header->response.reserved);
270  }
271 }
272 
273 rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc)
274 {
275  rpcconn_common_hdr_t header = { 0 };
276  WINPR_ASSERT(rpc);
277 
278  header.rpc_vers = rpc->rpc_vers;
279  header.rpc_vers_minor = rpc->rpc_vers_minor;
280  header.packed_drep[0] = rpc->packed_drep[0];
281  header.packed_drep[1] = rpc->packed_drep[1];
282  header.packed_drep[2] = rpc->packed_drep[2];
283  header.packed_drep[3] = rpc->packed_drep[3];
284  return header;
285 }
286 
287 size_t rpc_offset_align(size_t* offset, size_t alignment)
288 {
289  size_t pad = 0;
290  pad = *offset;
291  *offset = (*offset + alignment - 1) & ~(alignment - 1);
292  pad = *offset - pad;
293  return pad;
294 }
295 
296 size_t rpc_offset_pad(size_t* offset, size_t pad)
297 {
298  *offset += pad;
299  return pad;
300 }
301 
302 /*
303  * PDU Segments:
304  * ________________________________
305  * | |
306  * | PDU Header |
307  * |________________________________|
308  * | |
309  * | |
310  * | PDU Body |
311  * | |
312  * |________________________________|
313  * | |
314  * | Security Trailer |
315  * |________________________________|
316  * | |
317  * | Authentication Token |
318  * |________________________________|
319  */
320 
321 /*
322  * PDU Structure with verification trailer
323  *
324  * MUST only appear in a request PDU!
325  * ________________________________
326  * | |
327  * | PDU Header |
328  * |________________________________| _______
329  * | | /|\
330  * | | |
331  * | Stub Data | |
332  * | | |
333  * |________________________________| |
334  * | | PDU Body
335  * | Stub Pad | |
336  * |________________________________| |
337  * | | |
338  * | Verification Trailer | |
339  * |________________________________| |
340  * | | |
341  * | Authentication Pad | |
342  * |________________________________| __\|/__
343  * | |
344  * | Security Trailer |
345  * |________________________________|
346  * | |
347  * | Authentication Token |
348  * |________________________________|
349  *
350  */
351 
352 /*
353  * Security Trailer:
354  *
355  * The sec_trailer structure MUST be placed at the end of the PDU, including past stub data,
356  * when present. The sec_trailer structure MUST be 4-byte aligned with respect to the beginning
357  * of the PDU. Padding octets MUST be used to align the sec_trailer structure if its natural
358  * beginning is not already 4-byte aligned.
359  *
360  * All PDUs that carry sec_trailer information share certain common fields:
361  * frag_length and auth_length. The beginning of the sec_trailer structure for each PDU MUST be
362  * calculated to start from offset (frag_length – auth_length – 8) from the beginning of the PDU.
363  *
364  * Immediately after the sec_trailer structure, there MUST be a BLOB carrying the authentication
365  * information produced by the security provider. This BLOB is called the authentication token and
366  * MUST be of size auth_length. The size MUST also be equal to the length from the first octet
367  * immediately after the sec_trailer structure all the way to the end of the fragment;
368  * the two values MUST be the same.
369  *
370  * A client or a server that (during composing of a PDU) has allocated more space for the
371  * authentication token than the security provider fills in SHOULD fill in the rest of
372  * the allocated space with zero octets. These zero octets are still considered to belong
373  * to the authentication token part of the PDU.
374  *
375  */
376 
377 BOOL rpc_get_stub_data_info(rdpRpc* rpc, const rpcconn_hdr_t* header, size_t* poffset,
378  size_t* length)
379 {
380  size_t used = 0;
381  size_t offset = 0;
382  BOOL rc = FALSE;
383  UINT32 frag_length = 0;
384  UINT32 auth_length = 0;
385  UINT32 auth_pad_length = 0;
386  UINT32 sec_trailer_offset = 0;
387  const rpc_sec_trailer* sec_trailer = NULL;
388 
389  WINPR_ASSERT(rpc);
390  WINPR_ASSERT(header);
391  WINPR_ASSERT(poffset);
392  WINPR_ASSERT(length);
393 
394  offset = RPC_COMMON_FIELDS_LENGTH;
395 
396  switch (header->common.ptype)
397  {
398  case PTYPE_RESPONSE:
399  offset += 8;
400  rpc_offset_align(&offset, 8);
401  sec_trailer = &header->response.auth_verifier;
402  break;
403 
404  case PTYPE_REQUEST:
405  offset += 4;
406  rpc_offset_align(&offset, 8);
407  sec_trailer = &header->request.auth_verifier;
408  break;
409 
410  case PTYPE_RTS:
411  offset += 4;
412  break;
413 
414  default:
415  WLog_Print(rpc->log, WLOG_ERROR, "Unknown PTYPE: 0x%02" PRIX8 "", header->common.ptype);
416  goto fail;
417  }
418 
419  frag_length = header->common.frag_length;
420  auth_length = header->common.auth_length;
421 
422  if (poffset)
423  *poffset = offset;
424 
425  /* The fragment must be larger than the authentication trailer */
426  used = offset + auth_length + 8ull;
427  if (sec_trailer)
428  {
429  auth_pad_length = sec_trailer->auth_pad_length;
430  used += sec_trailer->auth_pad_length;
431  }
432 
433  if (frag_length < used)
434  goto fail;
435 
436  if (!length)
437  return TRUE;
438 
439  sec_trailer_offset = frag_length - auth_length - 8;
440 
441  /*
442  * According to [MS-RPCE], auth_pad_length is the number of padding
443  * octets used to 4-byte align the security trailer, but in practice
444  * we get values up to 15, which indicates 16-byte alignment.
445  */
446 
447  if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
448  {
449  WLog_Print(rpc->log, WLOG_ERROR,
450  "invalid auth_length: actual: %" PRIu32 ", expected: %" PRIu32 "", auth_length,
451  (frag_length - (sec_trailer_offset + 8)));
452  }
453 
454  *length = sec_trailer_offset - auth_pad_length - offset;
455 
456  rc = TRUE;
457 fail:
458  return rc;
459 }
460 
461 SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length)
462 {
463  int status = 0;
464 
465  if (!channel || (length > INT32_MAX))
466  return -1;
467 
468  ERR_clear_error();
469  status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
470 
471  if (status > 0)
472  {
473  Stream_Seek(s, (size_t)status);
474  return status;
475  }
476 
477  if (BIO_should_retry(channel->tls->bio))
478  return 0;
479 
480  WLog_Print(channel->rpc->log, WLOG_ERROR, "rpc_channel_read: Out of retries");
481  return -1;
482 }
483 
484 SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length)
485 {
486  if (!channel)
487  return -1;
488 
489  return freerdp_tls_write_all(channel->tls, data, length);
490 }
491 
492 BOOL rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
493 {
494  if (!inChannel)
495  return FALSE;
496 
497  inChannel->State = state;
498  WLog_Print(inChannel->common.rpc->log, WLOG_DEBUG, "%s", client_in_state_str(state));
499  return TRUE;
500 }
501 
502 static int rpc_channel_rpch_init(RpcClient* client, RpcChannel* channel, const char* inout,
503  const GUID* guid)
504 {
505  HttpContext* http = NULL;
506  rdpSettings* settings = NULL;
507  UINT32 timeout = 0;
508 
509  if (!client || !channel || !inout || !client->context || !client->context->settings)
510  return -1;
511 
512  settings = client->context->settings;
513  channel->auth = credssp_auth_new(client->context);
514  rts_generate_cookie((BYTE*)&channel->Cookie);
515  channel->client = client;
516 
517  if (!channel->auth)
518  return -1;
519 
520  channel->http = http_context_new();
521 
522  if (!channel->http)
523  return -1;
524 
525  http = channel->http;
526 
527  {
528  if (!http_context_set_pragma(http, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729"))
529  return -1;
530 
531  if (guid)
532  {
533  char* strguid = NULL;
534  RPC_STATUS rpcStatus = UuidToStringA(guid, &strguid);
535 
536  if (rpcStatus != RPC_S_OK)
537  return -1;
538 
539  const BOOL rc = http_context_append_pragma(http, "SessionId=%s", strguid);
540  RpcStringFreeA(&strguid);
541  if (!rc)
542  return -1;
543  }
544  if (timeout)
545  {
546  if (!http_context_append_pragma(http, "MinConnTimeout=%" PRIu32, timeout))
547  return -1;
548  }
549 
550  if (!http_context_set_rdg_correlation_id(http, guid) ||
551  !http_context_set_rdg_connection_id(http, guid))
552  return -1;
553  }
554 
555  /* TODO: "/rpcwithcert/rpcproxy.dll". */
556  if (!http_context_set_method(http, inout) ||
557  !http_context_set_uri(http, "/rpc/rpcproxy.dll?localhost:3388") ||
558  !http_context_set_accept(http, "application/rpc") ||
559  !http_context_set_cache_control(http, "no-cache") ||
560  !http_context_set_connection(http, "Keep-Alive") ||
561  !http_context_set_user_agent(http, "MSRPC") ||
562  !http_context_set_host(http, settings->GatewayHostname))
563  return -1;
564 
565  return 1;
566 }
567 
568 static int rpc_in_channel_init(rdpRpc* rpc, RpcInChannel* inChannel, const GUID* guid)
569 {
570  WINPR_ASSERT(rpc);
571  WINPR_ASSERT(inChannel);
572 
573  inChannel->common.rpc = rpc;
574  inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
575  inChannel->BytesSent = 0;
576  inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
577  inChannel->PingOriginator.ConnectionTimeout = 30;
578  inChannel->PingOriginator.KeepAliveInterval = 0;
579 
580  if (rpc_channel_rpch_init(rpc->client, &inChannel->common, "RPC_IN_DATA", guid) < 0)
581  return -1;
582 
583  return 1;
584 }
585 
586 static RpcInChannel* rpc_in_channel_new(rdpRpc* rpc, const GUID* guid)
587 {
588  RpcInChannel* inChannel = (RpcInChannel*)calloc(1, sizeof(RpcInChannel));
589 
590  if (inChannel)
591  {
592  rpc_in_channel_init(rpc, inChannel, guid);
593  }
594 
595  return inChannel;
596 }
597 
598 void rpc_channel_free(RpcChannel* channel)
599 {
600  if (!channel)
601  return;
602 
603  credssp_auth_free(channel->auth);
604  http_context_free(channel->http);
605  freerdp_tls_free(channel->tls);
606  free(channel);
607 }
608 
609 BOOL rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
610 {
611  if (!outChannel)
612  return FALSE;
613 
614  outChannel->State = state;
615  WLog_Print(outChannel->common.rpc->log, WLOG_DEBUG, "%s", client_out_state_str(state));
616  return TRUE;
617 }
618 
619 static int rpc_out_channel_init(rdpRpc* rpc, RpcOutChannel* outChannel, const GUID* guid)
620 {
621  WINPR_ASSERT(rpc);
622  WINPR_ASSERT(outChannel);
623 
624  outChannel->common.rpc = rpc;
625  outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
626  outChannel->BytesReceived = 0;
627  outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
628  outChannel->ReceiveWindow = rpc->ReceiveWindow;
629  outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
630  outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
631 
632  if (rpc_channel_rpch_init(rpc->client, &outChannel->common, "RPC_OUT_DATA", guid) < 0)
633  return -1;
634 
635  return 1;
636 }
637 
638 RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc, const GUID* guid)
639 {
640  RpcOutChannel* outChannel = (RpcOutChannel*)calloc(1, sizeof(RpcOutChannel));
641 
642  if (outChannel)
643  {
644  rpc_out_channel_init(rpc, outChannel, guid);
645  }
646 
647  return outChannel;
648 }
649 
650 BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc, RpcVirtualConnection* connection,
651  VIRTUAL_CONNECTION_STATE state)
652 {
653  if (!connection)
654  return FALSE;
655 
656  WINPR_ASSERT(rpc);
657  connection->State = state;
658  WLog_Print(rpc->log, WLOG_DEBUG, "%s", rpc_vc_state_str(state));
659  return TRUE;
660 }
661 
662 static void rpc_virtual_connection_free(RpcVirtualConnection* connection)
663 {
664  if (!connection)
665  return;
666 
667  if (connection->DefaultInChannel)
668  rpc_channel_free(&connection->DefaultInChannel->common);
669  if (connection->NonDefaultInChannel)
670  rpc_channel_free(&connection->NonDefaultInChannel->common);
671  if (connection->DefaultOutChannel)
672  rpc_channel_free(&connection->DefaultOutChannel->common);
673  if (connection->NonDefaultOutChannel)
674  rpc_channel_free(&connection->NonDefaultOutChannel->common);
675  free(connection);
676 }
677 
678 static RpcVirtualConnection* rpc_virtual_connection_new(rdpRpc* rpc)
679 {
680  WINPR_ASSERT(rpc);
681 
682  RpcVirtualConnection* connection =
683  (RpcVirtualConnection*)calloc(1, sizeof(RpcVirtualConnection));
684 
685  if (!connection)
686  return NULL;
687 
688  rts_generate_cookie((BYTE*)&(connection->Cookie));
689  rts_generate_cookie((BYTE*)&(connection->AssociationGroupId));
690  connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
691 
692  connection->DefaultInChannel = rpc_in_channel_new(rpc, &connection->Cookie);
693 
694  if (!connection->DefaultInChannel)
695  goto fail;
696 
697  connection->DefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
698 
699  if (!connection->DefaultOutChannel)
700  goto fail;
701 
702  return connection;
703 fail:
704  rpc_virtual_connection_free(connection);
705  return NULL;
706 }
707 
708 static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout)
709 {
710  if (!channel || !channel->client || !channel->client->context ||
711  !channel->client->context->settings)
712  return FALSE;
713 
714  rdpContext* context = channel->client->context;
715  WINPR_ASSERT(context);
716 
717  rdpSettings* settings = context->settings;
718  WINPR_ASSERT(settings);
719 
720  const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_ProxyUsername);
721  const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_ProxyPassword);
722 
723  rdpTransport* transport = freerdp_get_transport(context);
724  rdpTransportLayer* layer =
725  transport_connect_layer(transport, channel->client->host, channel->client->port, timeout);
726 
727  if (!layer)
728  return FALSE;
729 
730  BIO* layerBio = BIO_new(BIO_s_transport_layer());
731  if (!layerBio)
732  {
733  transport_layer_free(layer);
734  return FALSE;
735  }
736  BIO_set_data(layerBio, layer);
737 
738  BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
739  if (!bufferedBio)
740  {
741  BIO_free_all(layerBio);
742  return FALSE;
743  }
744 
745  bufferedBio = BIO_push(bufferedBio, layerBio);
746 
747  if (!BIO_set_nonblock(bufferedBio, TRUE))
748  {
749  BIO_free_all(bufferedBio);
750  return FALSE;
751  }
752 
753  if (channel->client->isProxy)
754  {
755  if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
756  settings->GatewayHostname, settings->GatewayPort))
757  {
758  BIO_free_all(bufferedBio);
759  return FALSE;
760  }
761  }
762 
763  channel->bio = bufferedBio;
764  rdpTls* tls = channel->tls = freerdp_tls_new(context);
765 
766  if (!tls)
767  return FALSE;
768 
769  tls->hostname = settings->GatewayHostname;
770  tls->port = MIN(UINT16_MAX, settings->GatewayPort);
771  tls->isGatewayTransport = TRUE;
772  int tlsStatus = freerdp_tls_connect(tls, bufferedBio);
773 
774  if (tlsStatus < 1)
775  {
776  if (tlsStatus < 0)
777  {
778  freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
779  }
780  else
781  {
782  freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
783  }
784 
785  return FALSE;
786  }
787 
788  return TRUE;
789 }
790 
791 static int rpc_in_channel_connect(RpcInChannel* inChannel, UINT32 timeout)
792 {
793  rdpContext* context = NULL;
794 
795  if (!inChannel || !inChannel->common.client || !inChannel->common.client->context)
796  return -1;
797 
798  context = inChannel->common.client->context;
799 
800  /* Connect IN Channel */
801 
802  if (!rpc_channel_tls_connect(&inChannel->common, timeout))
803  return -1;
804 
805  rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
806 
807  if (!rpc_ncacn_http_auth_init(context, &inChannel->common))
808  return -1;
809 
810  /* Send IN Channel Request */
811 
812  if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
813  {
814  WLog_Print(inChannel->common.rpc->log, WLOG_ERROR,
815  "rpc_ncacn_http_send_in_channel_request failure");
816  return -1;
817  }
818 
819  if (!rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY))
820  return -1;
821 
822  return 1;
823 }
824 
825 static int rpc_out_channel_connect(RpcOutChannel* outChannel, int timeout)
826 {
827  rdpContext* context = NULL;
828 
829  if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
830  return -1;
831 
832  context = outChannel->common.client->context;
833 
834  /* Connect OUT Channel */
835 
836  if (!rpc_channel_tls_connect(&outChannel->common, timeout))
837  return -1;
838 
839  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
840 
841  if (!rpc_ncacn_http_auth_init(context, &outChannel->common))
842  return FALSE;
843 
844  /* Send OUT Channel Request */
845 
846  if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
847  {
848  WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
849  "rpc_ncacn_http_send_out_channel_request failure");
850  return FALSE;
851  }
852 
853  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
854  return 1;
855 }
856 
857 int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout)
858 {
859  rdpContext* context = NULL;
860 
861  if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
862  return -1;
863 
864  context = outChannel->common.client->context;
865 
866  /* Connect OUT Channel */
867 
868  if (!rpc_channel_tls_connect(&outChannel->common, timeout))
869  return -1;
870 
871  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
872 
873  if (!rpc_ncacn_http_auth_init(context, (RpcChannel*)outChannel))
874  return FALSE;
875 
876  /* Send OUT Channel Request */
877 
878  if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, TRUE))
879  {
880  WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
881  "rpc_ncacn_http_send_out_channel_request failure");
882  return FALSE;
883  }
884 
885  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
886  return 1;
887 }
888 
889 BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
890 {
891  RpcInChannel* inChannel = NULL;
892  RpcOutChannel* outChannel = NULL;
893  RpcVirtualConnection* connection = NULL;
894  rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
895 
896  if (!rpc->VirtualConnection)
897  return FALSE;
898 
899  connection = rpc->VirtualConnection;
900  inChannel = connection->DefaultInChannel;
901  outChannel = connection->DefaultOutChannel;
902  rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
903 
904  if (rpc_in_channel_connect(inChannel, timeout) < 0)
905  return FALSE;
906 
907  if (rpc_out_channel_connect(outChannel, timeout) < 0)
908  return FALSE;
909 
910  return TRUE;
911 }
912 
913 rdpRpc* rpc_new(rdpTransport* transport)
914 {
915  rdpContext* context = transport_get_context(transport);
916  rdpRpc* rpc = NULL;
917 
918  WINPR_ASSERT(context);
919 
920  rpc = (rdpRpc*)calloc(1, sizeof(rdpRpc));
921 
922  if (!rpc)
923  return NULL;
924 
925  rpc->log = WLog_Get(TAG);
926  rpc->State = RPC_CLIENT_STATE_INITIAL;
927  rpc->transport = transport;
928  rpc->SendSeqNum = 0;
929  rpc->auth = credssp_auth_new(context);
930 
931  if (!rpc->auth)
932  goto out_free;
933 
934  rpc->PipeCallId = 0;
935  rpc->StubCallId = 0;
936  rpc->StubFragCount = 0;
937  rpc->rpc_vers = 5;
938  rpc->rpc_vers_minor = 0;
939  /* little-endian data representation */
940  rpc->packed_drep[0] = 0x10;
941  rpc->packed_drep[1] = 0x00;
942  rpc->packed_drep[2] = 0x00;
943  rpc->packed_drep[3] = 0x00;
944  rpc->max_xmit_frag = 0x0FF8;
945  rpc->max_recv_frag = 0x0FF8;
946  rpc->ReceiveWindow = 0x00010000;
947  rpc->ChannelLifetime = 0x40000000;
948  rpc->KeepAliveInterval = 300000;
949  rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
950  rpc->CurrentKeepAliveTime = 0;
951  rpc->CallId = 2;
952  rpc->client = rpc_client_new(context, rpc->max_recv_frag);
953 
954  if (!rpc->client)
955  goto out_free;
956 
957  return rpc;
958 out_free:
959  WINPR_PRAGMA_DIAG_PUSH
960  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
961  rpc_free(rpc);
962  WINPR_PRAGMA_DIAG_POP
963  return NULL;
964 }
965 
966 void rpc_free(rdpRpc* rpc)
967 {
968  if (rpc)
969  {
970  rpc_client_free(rpc->client);
971  credssp_auth_free(rpc->auth);
972  rpc_virtual_connection_free(rpc->VirtualConnection);
973  free(rpc);
974  }
975 }
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.