FreeRDP
ncacn_http.c
1 
20 #include <freerdp/config.h>
21 
22 #include "../settings.h"
23 #include "ncacn_http.h"
24 
25 #include <winpr/crt.h>
26 #include <winpr/tchar.h>
27 #include <winpr/stream.h>
28 #include <winpr/dsparse.h>
29 
30 #include "../utils.h"
31 
32 #define TAG FREERDP_TAG("core.gateway.ntlm")
33 
34 #define AUTH_PKG NTLM_SSP_NAME
35 
36 static wStream* rpc_auth_http_request(HttpContext* http, const char* method, int contentLength,
37  const SecBuffer* authToken, const char* auth_scheme)
38 {
39  wStream* s = NULL;
40  HttpRequest* request = NULL;
41  char* base64AuthToken = NULL;
42  const char* uri = NULL;
43 
44  if (!http || !method)
45  goto fail;
46 
47  request = http_request_new();
48 
49  if (!request)
50  goto fail;
51 
52  if (authToken)
53  base64AuthToken = crypto_base64_encode(authToken->pvBuffer, authToken->cbBuffer);
54 
55  uri = http_context_get_uri(http);
56 
57  if (!http_request_set_method(request, method) ||
58  !http_request_set_content_length(request, contentLength) ||
59  !http_request_set_uri(request, uri))
60  goto fail;
61 
62  if (base64AuthToken)
63  {
64  if (!http_request_set_auth_scheme(request, auth_scheme) ||
65  !http_request_set_auth_param(request, base64AuthToken))
66  goto fail;
67  }
68 
69  s = http_request_write(http, request);
70 fail:
71  http_request_free(request);
72  free(base64AuthToken);
73  return s;
74 }
75 
76 BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel)
77 {
78  wStream* s = NULL;
79  SSIZE_T status = 0;
80  int contentLength = 0;
81  rdpCredsspAuth* auth = NULL;
82  HttpContext* http = NULL;
83  const SecBuffer* buffer = NULL;
84  int rc = 0;
85 
86  if (!inChannel || !inChannel->auth || !inChannel->http)
87  return FALSE;
88 
89  auth = inChannel->auth;
90  http = inChannel->http;
91 
92  rc = credssp_auth_authenticate(auth);
93  if (rc < 0)
94  return FALSE;
95 
96  contentLength = (rc == 0) ? 0 : 0x40000000;
97  buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : NULL;
98  s = rpc_auth_http_request(http, "RPC_IN_DATA", contentLength, buffer,
99  credssp_auth_pkg_name(auth));
100 
101  if (!s)
102  return -1;
103 
104  status = rpc_channel_write(inChannel, Stream_Buffer(s), Stream_Length(s));
105  Stream_Free(s, TRUE);
106  return (status > 0) ? 1 : -1;
107 }
108 
109 BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response)
110 {
111  size_t authTokenLength = 0;
112  BYTE* authTokenData = NULL;
113 
114  if (!inChannel || !response || !inChannel->auth)
115  return FALSE;
116 
117  rdpCredsspAuth* auth = inChannel->auth;
118  const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
119 
120  if (token64)
121  crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
122 
123  if (authTokenLength > UINT32_MAX)
124  {
125  free(authTokenData);
126  return FALSE;
127  }
128 
129  SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
130 
131  if (authTokenData && authTokenLength)
132  {
133  credssp_auth_take_input_buffer(auth, &buffer);
134  return TRUE;
135  }
136 
137  sspi_SecBufferFree(&buffer);
138  return TRUE;
139 }
140 
141 BOOL rpc_ncacn_http_auth_init(rdpContext* context, RpcChannel* channel)
142 {
143  rdpTls* tls = NULL;
144  rdpCredsspAuth* auth = NULL;
145  rdpSettings* settings = NULL;
146  freerdp* instance = NULL;
147  auth_status rc = AUTH_FAILED;
148  SEC_WINNT_AUTH_IDENTITY identity = { 0 };
149 
150  if (!context || !channel)
151  return FALSE;
152 
153  tls = channel->tls;
154  auth = channel->auth;
155  settings = context->settings;
156  instance = context->instance;
157 
158  if (!tls || !auth || !instance || !settings)
159  return FALSE;
160 
161  rc = utils_authenticate_gateway(instance, GW_AUTH_HTTP);
162  switch (rc)
163  {
164  case AUTH_SUCCESS:
165  case AUTH_SKIP:
166  break;
167  case AUTH_CANCELLED:
168  freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
169  return FALSE;
170  case AUTH_NO_CREDENTIALS:
171  WLog_INFO(TAG, "No credentials provided - using NULL identity");
172  break;
173  case AUTH_FAILED:
174  default:
175  return FALSE;
176  }
177 
178  if (!credssp_auth_init(auth, AUTH_PKG, tls->Bindings))
179  return FALSE;
180 
181  if (!identity_set_from_settings(&identity, settings, FreeRDP_GatewayUsername,
182  FreeRDP_GatewayDomain, FreeRDP_GatewayPassword))
183  return FALSE;
184 
185  SEC_WINNT_AUTH_IDENTITY* identityArg = (settings->GatewayUsername ? &identity : NULL);
186  const BOOL res =
187  credssp_auth_setup_client(auth, "HTTP", settings->GatewayHostname, identityArg, NULL);
188 
189  sspi_FreeAuthIdentity(&identity);
190 
191  credssp_auth_set_flags(auth, ISC_REQ_CONFIDENTIALITY);
192 
193  return res;
194 }
195 
196 void rpc_ncacn_http_auth_uninit(RpcChannel* channel)
197 {
198  if (!channel)
199  return;
200 
201  credssp_auth_free(channel->auth);
202  channel->auth = NULL;
203 }
204 
205 BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replacement)
206 {
207  BOOL status = TRUE;
208  wStream* s = NULL;
209  int contentLength = 0;
210  rdpCredsspAuth* auth = NULL;
211  HttpContext* http = NULL;
212  const SecBuffer* buffer = NULL;
213  int rc = 0;
214 
215  if (!outChannel || !outChannel->auth || !outChannel->http)
216  return FALSE;
217 
218  auth = outChannel->auth;
219  http = outChannel->http;
220 
221  rc = credssp_auth_authenticate(auth);
222  if (rc < 0)
223  return FALSE;
224 
225  if (!replacement)
226  contentLength = (rc == 0) ? 0 : 76;
227  else
228  contentLength = (rc == 0) ? 0 : 120;
229 
230  buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : NULL;
231  s = rpc_auth_http_request(http, "RPC_OUT_DATA", contentLength, buffer,
232  credssp_auth_pkg_name(auth));
233 
234  if (!s)
235  return -1;
236 
237  if (rpc_channel_write(outChannel, Stream_Buffer(s), Stream_Length(s)) < 0)
238  status = FALSE;
239 
240  Stream_Free(s, TRUE);
241  return status;
242 }
243 
244 BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response)
245 {
246  size_t authTokenLength = 0;
247  BYTE* authTokenData = NULL;
248 
249  if (!outChannel || !response || !outChannel->auth)
250  return FALSE;
251 
252  rdpCredsspAuth* auth = outChannel->auth;
253  const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
254 
255  if (token64)
256  crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
257 
258  if (authTokenLength > UINT32_MAX)
259  {
260  free(authTokenData);
261  return FALSE;
262  }
263  SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
264 
265  if (authTokenData && authTokenLength)
266  {
267  credssp_auth_take_input_buffer(auth, &buffer);
268  return TRUE;
269  }
270 
271  sspi_SecBufferFree(&buffer);
272  return TRUE;
273 }
274 
275 BOOL rpc_ncacn_http_is_final_request(RpcChannel* channel)
276 {
277  WINPR_ASSERT(channel);
278  return credssp_auth_is_complete(channel->auth);
279 }