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, size_t 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  rdpCredsspAuth* auth = NULL;
81  HttpContext* http = NULL;
82  const SecBuffer* buffer = NULL;
83  int rc = 0;
84 
85  if (!inChannel || !inChannel->auth || !inChannel->http)
86  return FALSE;
87 
88  auth = inChannel->auth;
89  http = inChannel->http;
90 
91  rc = credssp_auth_authenticate(auth);
92  if (rc < 0)
93  return FALSE;
94 
95  const size_t contentLength = (rc == 0) ? 0 : 0x40000000;
96  buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : NULL;
97  s = rpc_auth_http_request(http, "RPC_IN_DATA", contentLength, buffer,
98  credssp_auth_pkg_name(auth));
99 
100  if (!s)
101  return -1;
102 
103  status = rpc_channel_write(inChannel, Stream_Buffer(s), Stream_Length(s));
104  Stream_Free(s, TRUE);
105  return (status > 0) ? 1 : -1;
106 }
107 
108 BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response)
109 {
110  size_t authTokenLength = 0;
111  BYTE* authTokenData = NULL;
112 
113  if (!inChannel || !response || !inChannel->auth)
114  return FALSE;
115 
116  rdpCredsspAuth* auth = inChannel->auth;
117  const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
118 
119  if (token64)
120  crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
121 
122  if (authTokenLength > UINT32_MAX)
123  {
124  free(authTokenData);
125  return FALSE;
126  }
127 
128  SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
129 
130  if (authTokenData && authTokenLength)
131  {
132  credssp_auth_take_input_buffer(auth, &buffer);
133  return TRUE;
134  }
135 
136  sspi_SecBufferFree(&buffer);
137  return TRUE;
138 }
139 
140 BOOL rpc_ncacn_http_auth_init(rdpContext* context, RpcChannel* channel)
141 {
142  rdpTls* tls = NULL;
143  rdpCredsspAuth* auth = NULL;
144  rdpSettings* settings = NULL;
145  freerdp* instance = NULL;
146  auth_status rc = AUTH_FAILED;
147  SEC_WINNT_AUTH_IDENTITY identity = { 0 };
148 
149  if (!context || !channel)
150  return FALSE;
151 
152  tls = channel->tls;
153  auth = channel->auth;
154  settings = context->settings;
155  instance = context->instance;
156 
157  if (!tls || !auth || !instance || !settings)
158  return FALSE;
159 
160  rc = utils_authenticate_gateway(instance, GW_AUTH_HTTP);
161  switch (rc)
162  {
163  case AUTH_SUCCESS:
164  case AUTH_SKIP:
165  break;
166  case AUTH_CANCELLED:
167  freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
168  return FALSE;
169  case AUTH_NO_CREDENTIALS:
170  WLog_INFO(TAG, "No credentials provided - using NULL identity");
171  break;
172  case AUTH_FAILED:
173  default:
174  return FALSE;
175  }
176 
177  if (!credssp_auth_init(auth, AUTH_PKG, tls->Bindings))
178  return FALSE;
179 
180  if (!identity_set_from_settings(&identity, settings, FreeRDP_GatewayUsername,
181  FreeRDP_GatewayDomain, FreeRDP_GatewayPassword))
182  return FALSE;
183 
184  SEC_WINNT_AUTH_IDENTITY* identityArg = (settings->GatewayUsername ? &identity : NULL);
185  const BOOL res =
186  credssp_auth_setup_client(auth, "HTTP", settings->GatewayHostname, identityArg, NULL);
187 
188  sspi_FreeAuthIdentity(&identity);
189 
190  credssp_auth_set_flags(auth, ISC_REQ_CONFIDENTIALITY);
191 
192  return res;
193 }
194 
195 void rpc_ncacn_http_auth_uninit(RpcChannel* channel)
196 {
197  if (!channel)
198  return;
199 
200  credssp_auth_free(channel->auth);
201  channel->auth = NULL;
202 }
203 
204 BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replacement)
205 {
206  BOOL status = TRUE;
207  wStream* s = NULL;
208  size_t contentLength = 0;
209  rdpCredsspAuth* auth = NULL;
210  HttpContext* http = NULL;
211  const SecBuffer* buffer = NULL;
212  int rc = 0;
213 
214  if (!outChannel || !outChannel->auth || !outChannel->http)
215  return FALSE;
216 
217  auth = outChannel->auth;
218  http = outChannel->http;
219 
220  rc = credssp_auth_authenticate(auth);
221  if (rc < 0)
222  return FALSE;
223 
224  if (!replacement)
225  contentLength = (rc == 0) ? 0 : 76;
226  else
227  contentLength = (rc == 0) ? 0 : 120;
228 
229  buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : NULL;
230  s = rpc_auth_http_request(http, "RPC_OUT_DATA", contentLength, buffer,
231  credssp_auth_pkg_name(auth));
232 
233  if (!s)
234  return -1;
235 
236  if (rpc_channel_write(outChannel, Stream_Buffer(s), Stream_Length(s)) < 0)
237  status = FALSE;
238 
239  Stream_Free(s, TRUE);
240  return status;
241 }
242 
243 BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response)
244 {
245  size_t authTokenLength = 0;
246  BYTE* authTokenData = NULL;
247 
248  if (!outChannel || !response || !outChannel->auth)
249  return FALSE;
250 
251  rdpCredsspAuth* auth = outChannel->auth;
252  const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
253 
254  if (token64)
255  crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
256 
257  if (authTokenLength > UINT32_MAX)
258  {
259  free(authTokenData);
260  return FALSE;
261  }
262  SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
263 
264  if (authTokenData && authTokenLength)
265  {
266  credssp_auth_take_input_buffer(auth, &buffer);
267  return TRUE;
268  }
269 
270  sspi_SecBufferFree(&buffer);
271  return TRUE;
272 }
273 
274 BOOL rpc_ncacn_http_is_final_request(RpcChannel* channel)
275 {
276  WINPR_ASSERT(channel);
277  return credssp_auth_is_complete(channel->auth);
278 }