libfreerdp-core: start using HTTP utils for NTLM HTTP authentication

This commit is contained in:
Marc-André Moreau 2012-04-16 16:21:46 -04:00
parent 883b04d51f
commit fa7900d293
7 changed files with 402 additions and 234 deletions

View File

@ -142,6 +142,7 @@ FREERDP_API void crypto_rsa_private_decrypt(const uint8* input, int length, uint
FREERDP_API void crypto_reverse(uint8* data, int length); FREERDP_API void crypto_reverse(uint8* data, int length);
FREERDP_API void crypto_nonce(uint8* nonce, int size); FREERDP_API void crypto_nonce(uint8* nonce, int size);
FREERDP_API char* crypto_encode_base64(uint8* data, int length);
FREERDP_API void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_length); FREERDP_API void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_length);
FREERDP_API void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length); FREERDP_API void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length);

View File

@ -97,9 +97,19 @@ void http_request_set_uri(HttpRequest* http_request, char* uri)
http_request->URI = xstrdup(uri); http_request->URI = xstrdup(uri);
} }
void http_request_set_auth_scheme(HttpRequest* http_request, char* auth_scheme)
{
http_request->AuthScheme = xstrdup(auth_scheme);
}
void http_request_set_auth_param(HttpRequest* http_request, char* auth_param)
{
http_request->AuthParam = xstrdup(auth_param);
}
#define http_encode_line(_str, _fmt, ...) \ #define http_encode_line(_str, _fmt, ...) \
_str = xmalloc(snprintf(NULL, 0, _fmt, ## __VA_ARGS__)); \ _str = xmalloc(snprintf(NULL, 0, _fmt, ## __VA_ARGS__) + 1); \
snprintf(_str, snprintf(NULL, 0, _fmt, ## __VA_ARGS__), _fmt, ## __VA_ARGS__); snprintf(_str, snprintf(NULL, 0, _fmt, ## __VA_ARGS__) + 1, _fmt, ## __VA_ARGS__);
STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request) STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request)
{ {
@ -107,34 +117,49 @@ STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request)
STREAM* s; STREAM* s;
int length = 0; int length = 0;
http_request->count = 10; http_request->count = 9;
http_request->lines = (char**) xmalloc(sizeof(char*) * http_request->count); http_request->lines = (char**) xmalloc(sizeof(char*) * http_request->count);
http_encode_line(http_request->lines[0], "%s %s HTTP/1.1\n", http_request->Method, http_request->URI); http_encode_line(http_request->lines[0], "%s %s HTTP/1.1", http_request->Method, http_request->URI);
http_encode_line(http_request->lines[1], "Accept: %s\n", http_context->Accept); http_encode_line(http_request->lines[1], "Accept: %s", http_context->Accept);
http_encode_line(http_request->lines[2], "Cache-Control: %s\n", http_context->CacheControl); http_encode_line(http_request->lines[2], "Cache-Control: %s", http_context->CacheControl);
http_encode_line(http_request->lines[3], "Connection: %s\n", http_context->Connection); http_encode_line(http_request->lines[3], "Connection: %s", http_context->Connection);
http_encode_line(http_request->lines[4], "Content-Length: %d\n", http_request->ContentLength); http_encode_line(http_request->lines[4], "Content-Length: %d", http_request->ContentLength);
http_encode_line(http_request->lines[5], "User-Agent: %s\n", http_context->UserAgent); http_encode_line(http_request->lines[5], "User-Agent: %s", http_context->UserAgent);
http_encode_line(http_request->lines[6], "Host: %s\n", http_context->Host); http_encode_line(http_request->lines[6], "Host: %s", http_context->Host);
http_encode_line(http_request->lines[7], "Pragma: %s\n", http_context->Pragma); http_encode_line(http_request->lines[7], "Pragma: %s", http_context->Pragma);
http_encode_line(http_request->lines[8], "Authorization: %s\n", http_request->Authorization);
http_encode_line(http_request->lines[9], "\n\n"); if (http_request->Authorization != NULL)
{
http_encode_line(http_request->lines[8], "Authorization: %s", http_request->Authorization);
}
else if ((http_request->AuthScheme != NULL) && (http_request->AuthParam != NULL))
{
http_encode_line(http_request->lines[8], "Authorization: %s %s",
http_request->AuthScheme, http_request->AuthParam);
}
for (i = 0; i < http_request->count; i++) for (i = 0; i < http_request->count; i++)
{ {
length += strlen(http_request->lines[i]); length += (strlen(http_request->lines[i]) + 1); /* add +1 for each '\n' character */
} }
length += 1; /* empty line "\n" at end of header */
length += 1; /* null terminator */
s = stream_new(length); s = stream_new(length);
for (i = 0; i < http_request->count; i++) for (i = 0; i < http_request->count; i++)
{ {
stream_write(s, http_request->lines[i], strlen(http_request->lines[i])); stream_write(s, http_request->lines[i], strlen(http_request->lines[i]));
stream_write(s, "\n", 1);
xfree(http_request->lines[i]); xfree(http_request->lines[i]);
} }
stream_write(s, "\n", 1);
xfree(http_request->lines); xfree(http_request->lines);
stream_write(s, "\0", 1); /* append null terminator */
stream_rewind(s, 1); /* don't include null terminator in length */
stream_seal(s); stream_seal(s);
return s; return s;
@ -161,3 +186,228 @@ void http_request_free(HttpRequest* http_request)
xfree(http_request); xfree(http_request);
} }
} }
void http_response_parse_header_status_line(HttpResponse* http_response, char* status_line)
{
char* separator;
char* status_code;
char* reason_phrase;
separator = strchr(status_line, ' ');
status_code = separator + 1;
separator = strchr(status_code, ' ');
reason_phrase = separator + 1;
*separator = '\0';
http_response->StatusCode = atoi(status_code);
http_response->ReasonPhrase = xstrdup(reason_phrase);
*separator = ' ';
}
void http_response_parse_header_field(HttpResponse* http_response, char* name, char* value)
{
if (strcmp(name, "Content-Length") == 0)
{
http_response->ContentLength = atoi(value);
}
else if (strcmp(name, "Authorization") == 0)
{
char* separator;
http_response->Authorization = xstrdup(value);
separator = strchr(value, ' ');
if (separator != NULL)
{
*separator = '\0';
http_response->AuthScheme = xstrdup(value);
http_response->AuthParam = xstrdup(separator + 1);
*separator = ' ';
}
}
else if (strcmp(name, "WWW-Authenticate") == 0)
{
char* separator;
separator = strstr(value, "=\"");
if (separator != NULL)
{
/* WWW-Authenticate: parameter with spaces="value" */
return;
}
separator = strchr(value, ' ');
if (separator != NULL)
{
/* WWW-Authenticate: NTLM base64token */
*separator = '\0';
http_response->AuthScheme = xstrdup(value);
http_response->AuthParam = xstrdup(separator + 1);
*separator = ' ';
return;
}
}
}
void http_response_parse_header(HttpResponse* http_response)
{
int count;
char* line;
char* name;
char* value;
char* separator;
http_response_parse_header_status_line(http_response, http_response->lines[0]);
for (count = 1; count < http_response->count; count++)
{
line = http_response->lines[count];
separator = strstr(line, ": ");
if (separator == NULL)
continue;
separator[0] = '\0';
separator[1] = '\0';
name = line;
value = separator + 2;
printf("%s:%s\n", name, value);
http_response_parse_header_field(http_response, name, value);
separator[0] = ':';
separator[1] = ' ';
}
}
HttpResponse* http_response_recv(rdpTls* tls)
{
uint8* p;
int nbytes;
int length;
int status;
uint8* buffer;
char* content;
char* header_end;
HttpResponse* http_response;
nbytes = 0;
length = 2048;
buffer = xmalloc(length);
http_response = http_response_new();
p = buffer;
while (true)
{
status = tls_read(tls, p, length - nbytes);
if (status > 0)
{
nbytes += status;
p = (uint8*) &buffer[nbytes];
}
else if (status == 0)
{
continue;
}
else
{
return NULL;
break;
}
header_end = strstr((char*) buffer, "\r\n\r\n") + 2;
if (header_end != NULL)
{
int count;
char* line;
header_end[0] = '\0';
header_end[1] = '\0';
content = &header_end[2];
count = 0;
line = (char*) buffer;
while ((line = strstr(line, "\r\n")) != NULL)
{
line++;
count++;
}
http_response->count = count;
http_response->lines = (char**) xmalloc(sizeof(char*) * http_response->count);
count = 0;
line = strtok((char*) buffer, "\r\n");
while (line != NULL)
{
http_response->lines[count] = xstrdup(line);
line = strtok(NULL, "\r\n");
count++;
}
http_response_parse_header(http_response);
if (http_response->ContentLength > 0)
{
http_response->Content = xstrdup(content);
printf("Content: (%d)\n%s\n", http_response->ContentLength,
http_response->Content);
}
break;
}
}
return http_response;
}
HttpResponse* http_response_new()
{
HttpResponse* http_response = xnew(HttpResponse);
if (http_response != NULL)
{
}
return http_response;
}
void http_response_free(HttpResponse* http_response)
{
int i;
if (http_response != NULL)
{
for (i = 0; i < http_response->count; i++)
xfree(http_response->lines[i]);
xfree(http_response->lines);
xfree(http_response->ReasonPhrase);
xfree(http_response->AuthParam);
xfree(http_response->AuthScheme);
xfree(http_response->Authorization);
if (http_response->ContentLength > 0)
xfree(http_response->Content);
xfree(http_response);
}
}

View File

@ -20,7 +20,12 @@
#ifndef FREERDP_CORE_HTTP_H #ifndef FREERDP_CORE_HTTP_H
#define FREERDP_CORE_HTTP_H #define FREERDP_CORE_HTTP_H
typedef struct _http_context HttpContext;
typedef struct _http_request HttpRequest;
typedef struct _http_response HttpResponse;
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/crypto/tls.h>
#include <freerdp/utils/stream.h> #include <freerdp/utils/stream.h>
struct _http_context struct _http_context
@ -34,7 +39,6 @@ struct _http_context
char* Connection; char* Connection;
char* Pragma; char* Pragma;
}; };
typedef struct _http_context HttpContext;
void http_context_set_method(HttpContext* http_context, char* method); void http_context_set_method(HttpContext* http_context, char* method);
void http_context_set_uri(HttpContext* http_context, char* uri); void http_context_set_uri(HttpContext* http_context, char* uri);
@ -55,18 +59,41 @@ struct _http_request
char* Method; char* Method;
char* URI; char* URI;
char* AuthScheme;
char* AuthParam;
char* Authorization; char* Authorization;
int ContentLength; int ContentLength;
char* Content; char* Content;
}; };
typedef struct _http_request HttpRequest;
void http_request_set_method(HttpRequest* http_request, char* method); void http_request_set_method(HttpRequest* http_request, char* method);
void http_request_set_uri(HttpRequest* http_request, char* uri); void http_request_set_uri(HttpRequest* http_request, char* uri);
void http_request_set_auth_scheme(HttpRequest* http_request, char* auth_scheme);
void http_request_set_auth_param(HttpRequest* http_request, char* auth_param);
STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request); STREAM* http_request_write(HttpContext* http_context, HttpRequest* http_request);
HttpRequest* http_request_new(); HttpRequest* http_request_new();
void http_request_free(HttpRequest* http_request); void http_request_free(HttpRequest* http_request);
struct _http_response
{
int count;
char** lines;
int StatusCode;
char* ReasonPhrase;
char* AuthScheme;
char* AuthParam;
char* Authorization;
int ContentLength;
char* Content;
};
HttpResponse* http_response_recv(rdpTls* tls);
HttpResponse* http_response_new();
void http_response_free(HttpResponse* http_response);
#endif /* FREERDP_CORE_HTTP_H */ #endif /* FREERDP_CORE_HTTP_H */

View File

@ -169,62 +169,42 @@ void ntlm_free(rdpNtlm* ntlm)
} }
} }
STREAM* rpch_ntlm_http_data(rdpRpch* rpch, char* command, SecBuffer* ntlm_token, uint8* content, int length) STREAM* rpc_ntlm_http_data(rdpRpch* rpch, char* command, SecBuffer* ntlm_token, uint8* content, int length)
{ {
STREAM* s; STREAM* s;
char* int_str; char* base64_ntlm_token;
int total_length; HttpContext* http_context;
int int_str_length; HttpRequest* http_request;
int command_length;
rdpSettings* settings;
int tsg_hostname_length;
int ntlm_token_base64_length;
uint8* ntlm_token_base64_data;
settings = rpch->settings; base64_ntlm_token = crypto_encode_base64(ntlm_token->pvBuffer, ntlm_token->cbBuffer);
command_length = strlen(command); printf("base64_ntlm_token length:%d\n", strlen(base64_ntlm_token));
int_str_length = snprintf(NULL, 0, "%d", length); if (strcmp(command, "RPC_IN_DATA") == 0)
tsg_hostname_length = strlen(settings->tsg_hostname); http_context = rpch->http_in->context;
else
http_context = rpch->http_out->context;
int_str = xmalloc(int_str_length + 1); http_request = http_request_new();
snprintf(int_str, int_str_length + 1, "%d", length);
crypto_base64_encode(ntlm_token->pvBuffer, ntlm_token->cbBuffer, &ntlm_token_base64_data, &ntlm_token_base64_length); http_request->ContentLength = length;
total_length = 55 + 24 + 24 + 23 + 16 + int_str_length + 1 + 18 + 6 + http_request_set_method(http_request, http_context->Method);
tsg_hostname_length + 1 + 110 + 20 + ntlm_token_base64_length + 2; http_request_set_uri(http_request, http_context->URI);
s = stream_new(total_length); http_request_set_auth_scheme(http_request, "NTLM");
http_request_set_auth_param(http_request, base64_ntlm_token);
stream_write(s, command, command_length); s = http_request_write(http_context, http_request);
stream_write(s, " /rpc/rpcproxy.dll?localhost:3388 HTTP/1.1\n", 43);
stream_write(s, "Accept: application/rpc\n", 24);
stream_write(s, "Cache-Control: no-cache\n", 24);
stream_write(s, "Connection: Keep-Alive\n", 23);
stream_write(s, "Content-Length: ", 16);
stream_write(s, int_str, int_str_length);
stream_write(s, "\n", 1);
stream_write(s, "User-Agent: MSRPC\n", 18);
stream_write(s, "Host: ", 6);
stream_write(s, settings->tsg_hostname, tsg_hostname_length);
stream_write(s, "\n", 1);
stream_write(s, "Pragma: ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, SessionId=33ad20ac-7469-4f63-946d-113eac21a23c\n", 110);
stream_write(s, "Authorization: NTLM ", 20);
stream_write(s, ntlm_token_base64_data, ntlm_token_base64_length);
stream_write(s, "\n\n", 2);
stream_seal(s);
return s; return s;
} }
boolean rpch_out_connect_http(rdpRpch* rpch) boolean rpc_out_connect_http(rdpRpch* rpch)
{ {
STREAM* http_stream; STREAM* http_stream;
STREAM* ntlm_stream; STREAM* ntlm_stream;
HttpResponse* http_response;
int decoded_ntlm_http_length; int decoded_ntlm_http_length;
int encoded_ntlm_http_length; int encoded_ntlm_http_length;
uint8* decoded_ntlm_http_data = NULL; uint8* decoded_ntlm_http_data = NULL;
@ -236,13 +216,13 @@ boolean rpch_out_connect_http(rdpRpch* rpch)
ntlm_stream = stream_new(0); ntlm_stream = stream_new(0);
printf("rpch_out_connect_http\n"); printf("rpc_out_connect_http\n");
ntlm_client_init(http_out_ntlm, settings->username, settings->password, settings->domain); ntlm_client_init(http_out_ntlm, settings->username, settings->password, settings->domain);
ntlm_authenticate(http_out_ntlm); ntlm_authenticate(http_out_ntlm);
http_stream = rpch_ntlm_http_data(rpch, "RPC_OUT_DATA", &http_out_ntlm->outputBuffer, NULL, 0); http_stream = rpc_ntlm_http_data(rpch, "RPC_OUT_DATA", &http_out_ntlm->outputBuffer, NULL, 0);
DEBUG_RPCH("\nSend:\n%s\n", http_stream->data); DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
tls_write(tls_out, http_stream->data, http_stream->size); tls_write(tls_out, http_stream->data, http_stream->size);
@ -256,73 +236,15 @@ boolean rpch_out_connect_http(rdpRpch* rpch)
uint8 buffer_byte; uint8 buffer_byte;
http_out->contentLength = 0; http_out->contentLength = 0;
/* Example for how not to do clear code, sorry for that */ http_response = http_response_recv(tls_out);
while (true) /* TODO make proper reading */
{
tls_read(tls_out, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
if (encoded_ntlm_http_length == -1)
{
uint8* start_of_ntlm_http_data = (uint8*) strstr((char*) http_stream->data, "NTLM ");
if (start_of_ntlm_http_data != NULL)
{
start_of_ntlm_http_data += 5;
for (encoded_ntlm_http_length = 0; ; encoded_ntlm_http_length++)
{
tls_read(tls_out, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
if (start_of_ntlm_http_data[encoded_ntlm_http_length] == '\n')
{
encoded_ntlm_http_length--; /* \r */
break;
}
}
encoded_ntlm_http_data = xmalloc(encoded_ntlm_http_length);
memcpy(encoded_ntlm_http_data, start_of_ntlm_http_data, encoded_ntlm_http_length);
}
}
if (http_out->contentLength == 0)
{
if (strstr((char*) http_stream->data, "Content-Length: ") != NULL)
{
int i = 0;
while (*(http_stream->p-1) != '\n')
{
tls_read(tls_out, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
i++;
}
http_out->contentLength = strtol((char*)(http_stream->p - i), NULL, 10);
}
}
if (*(http_stream->p - 1) == '\n' && *(http_stream->p - 3) == '\n')
{
int i;
for (i = 0; i < http_out->contentLength; i++)
{
tls_read(tls_out, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
}
break;
}
}
/* Example end */
DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data); DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data);
stream_clear(http_stream); stream_clear(http_stream);
http_stream->p = http_stream->data; http_stream->p = http_stream->data;
encoded_ntlm_http_data = http_response->AuthParam;
encoded_ntlm_http_length = strlen(encoded_ntlm_http_data);
if (encoded_ntlm_http_length == 0) /* No NTLM data was found */ if (encoded_ntlm_http_length == 0) /* No NTLM data was found */
return false; return false;
@ -336,7 +258,7 @@ boolean rpch_out_connect_http(rdpRpch* rpch)
http_out->contentLength = 76; http_out->contentLength = 76;
http_out->remContentLength = 76; http_out->remContentLength = 76;
http_stream = rpch_ntlm_http_data(rpch, "RPC_OUT_DATA", &http_out_ntlm->outputBuffer, NULL, http_out->contentLength); http_stream = rpc_ntlm_http_data(rpch, "RPC_OUT_DATA", &http_out_ntlm->outputBuffer, NULL, http_out->contentLength);
DEBUG_RPCH("\nSend:\n%s\n", http_stream->data); DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
tls_write(tls_out, http_stream->data, http_stream->size); tls_write(tls_out, http_stream->data, http_stream->size);
@ -351,10 +273,11 @@ boolean rpch_out_connect_http(rdpRpch* rpch)
return true; return true;
} }
boolean rpch_in_connect_http(rdpRpch* rpch) boolean rpc_in_connect_http(rdpRpch* rpch)
{ {
STREAM* ntlm_stream; STREAM* ntlm_stream;
STREAM* http_stream; STREAM* http_stream;
HttpResponse* http_response;
int decoded_ntlm_http_length; int decoded_ntlm_http_length;
int encoded_ntlm_http_length; int encoded_ntlm_http_length;
uint8* decoded_ntlm_http_data = NULL; uint8* decoded_ntlm_http_data = NULL;
@ -372,7 +295,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch)
ntlm_authenticate(http_in_ntlm); ntlm_authenticate(http_in_ntlm);
http_stream = rpch_ntlm_http_data(rpch, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, 0); http_stream = rpc_ntlm_http_data(rpch, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, 0);
DEBUG_RPCH("\nSend:\n%s\n", http_stream->data); DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
tls_write(tls_in, http_stream->data, http_stream->size); tls_write(tls_in, http_stream->data, http_stream->size);
@ -388,73 +311,15 @@ boolean rpch_in_connect_http(rdpRpch* rpch)
uint8 buffer_byte; uint8 buffer_byte;
http_in->contentLength = 0; http_in->contentLength = 0;
/* Example for how not to do clear code, sorry for that */ http_response = http_response_recv(tls_in);
while (true) /* TODO make proper reading */
{
tls_read(tls_in, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
if (encoded_ntlm_http_length == -1)
{
uint8* start_of_ntht_data = (uint8*) strstr((char*) http_stream->data, "NTLM ");
if (start_of_ntht_data != NULL)
{
start_of_ntht_data += 5;
for (encoded_ntlm_http_length=0;;encoded_ntlm_http_length++)
{
tls_read(tls_in, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
if (start_of_ntht_data[encoded_ntlm_http_length]=='\n')
{
encoded_ntlm_http_length--; /* \r */
break;
}
}
encoded_ntlm_http_data = xmalloc(encoded_ntlm_http_length);
memcpy(encoded_ntlm_http_data, start_of_ntht_data, encoded_ntlm_http_length);
}
}
if (http_in->contentLength == 0)
{
if (strstr((char*) http_stream->data, "Content-Length: ") != NULL)
{
int i = 0;
while (*(http_stream->p-1) != '\n')
{
tls_read(tls_in, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
i++;
}
http_in->contentLength = strtol((char*)(http_stream->p-i), NULL, 10);
}
}
if (*(http_stream->p - 1) == '\n' && *(http_stream->p - 3) == '\n')
{
int i;
for(i = 0; i < http_in->contentLength; i++)
{
tls_read(tls_in, &buffer_byte, 1);
stream_write(http_stream, &buffer_byte, 1);
}
break;
}
}
/* Example end */
DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data); DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data);
stream_clear(http_stream); stream_clear(http_stream);
http_stream->p = http_stream->data; http_stream->p = http_stream->data;
encoded_ntlm_http_data = http_response->AuthParam;
encoded_ntlm_http_length = strlen(encoded_ntlm_http_data);
if (encoded_ntlm_http_length == 0) /* No NTLM data was found */ if (encoded_ntlm_http_length == 0) /* No NTLM data was found */
return false; return false;
@ -468,7 +333,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch)
http_in->contentLength = 1073741824; http_in->contentLength = 1073741824;
http_in->remContentLength = 1073741824; http_in->remContentLength = 1073741824;
http_stream = rpch_ntlm_http_data(rpch, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, http_in->contentLength); http_stream = rpc_ntlm_http_data(rpch, "RPC_IN_DATA", &http_in_ntlm->outputBuffer, NULL, http_in->contentLength);
DEBUG_RPCH("\nSend:\n%s\n", http_stream->data); DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
@ -486,7 +351,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch)
return true; return true;
} }
int rpch_out_write(rdpRpch* rpch, uint8* data, int length) int rpc_out_write(rdpRpch* rpch, uint8* data, int length)
{ {
int sent = 0; int sent = 0;
int status = -1; int status = -1;
@ -495,7 +360,7 @@ int rpch_out_write(rdpRpch* rpch, uint8* data, int length)
if (http_out->state == RPCH_HTTP_DISCONNECTED) if (http_out->state == RPCH_HTTP_DISCONNECTED)
{ {
if (!rpch_out_connect_http(rpch)) if (!rpc_out_connect_http(rpch))
return false; return false;
} }
@ -526,7 +391,7 @@ int rpch_out_write(rdpRpch* rpch, uint8* data, int length)
return sent; return sent;
} }
int rpch_in_write(rdpRpch* rpch, uint8* data, int length) int rpc_in_write(rdpRpch* rpch, uint8* data, int length)
{ {
int sent = 0; int sent = 0;
int status = -1; int status = -1;
@ -535,7 +400,7 @@ int rpch_in_write(rdpRpch* rpch, uint8* data, int length)
if (http_in->state == RPCH_HTTP_DISCONNECTED) if (http_in->state == RPCH_HTTP_DISCONNECTED)
{ {
if (!rpch_in_connect_http(rpch)) if (!rpc_in_connect_http(rpch))
return -1; return -1;
} }
@ -567,14 +432,14 @@ int rpch_in_write(rdpRpch* rpch, uint8* data, int length)
return sent; return sent;
} }
uint8* rpch_create_cookie() uint8* rpc_create_cookie()
{ {
uint8* ret = xmalloc(16); uint8* ret = xmalloc(16);
RAND_pseudo_bytes(ret, 16); RAND_pseudo_bytes(ret, 16);
return ret; return ret;
} }
boolean rpch_out_send_CONN_A1(rdpRpch* rpch) boolean rpc_out_send_CONN_A1(rdpRpch* rpch)
{ {
STREAM* pdu = stream_new(76); STREAM* pdu = stream_new(76);
@ -597,8 +462,8 @@ boolean rpch_out_send_CONN_A1(rdpRpch* rpch)
uint32 rwsCommandType = 0x00000000; uint32 rwsCommandType = 0x00000000;
uint32 receiveWindowSize = 0x00010000; uint32 receiveWindowSize = 0x00010000;
rpch->virtualConnectionCookie = rpch_create_cookie(); /* 16 bytes */ rpch->virtualConnectionCookie = rpc_create_cookie(); /* 16 bytes */
rpch->OUTChannelCookie = rpch_create_cookie(); /* 16 bytes */ rpch->OUTChannelCookie = rpc_create_cookie(); /* 16 bytes */
rpch->AwailableWindow = receiveWindowSize; rpch->AwailableWindow = receiveWindowSize;
stream_write_uint8(pdu, rpc_vers); stream_write_uint8(pdu, rpc_vers);
@ -620,14 +485,14 @@ boolean rpch_out_send_CONN_A1(rdpRpch* rpch)
stream_write_uint32(pdu, rwsCommandType); stream_write_uint32(pdu, rwsCommandType);
stream_write_uint32(pdu, receiveWindowSize); stream_write_uint32(pdu, receiveWindowSize);
rpch_out_write(rpch, pdu->data, stream_get_length(pdu)); rpc_out_write(rpch, pdu->data, stream_get_length(pdu));
stream_free(pdu); stream_free(pdu);
return true; return true;
} }
boolean rpch_in_send_CONN_B1(rdpRpch* rpch) boolean rpc_in_send_CONN_B1(rdpRpch* rpch)
{ {
STREAM* s = stream_new(104); STREAM* s = stream_new(104);
@ -654,8 +519,8 @@ boolean rpch_in_send_CONN_B1(rdpRpch* rpch)
uint32 agidCommandType = 0x0000000c; uint32 agidCommandType = 0x0000000c;
uint8* AssociationGroupId; uint8* AssociationGroupId;
rpch->INChannelCookie = rpch_create_cookie(); /* 16 bytes */ rpch->INChannelCookie = rpc_create_cookie(); /* 16 bytes */
AssociationGroupId = rpch_create_cookie(); /* 16 bytes */ AssociationGroupId = rpc_create_cookie(); /* 16 bytes */
stream_write_uint8(s, rpc_vers); stream_write_uint8(s, rpc_vers);
stream_write_uint8(s, rpc_vers_minor); stream_write_uint8(s, rpc_vers_minor);
@ -681,14 +546,14 @@ boolean rpch_in_send_CONN_B1(rdpRpch* rpch)
stream_write(s, AssociationGroupId, 16); stream_write(s, AssociationGroupId, 16);
stream_seal(s); stream_seal(s);
rpch_in_write(rpch, s->data, s->size); rpc_in_write(rpch, s->data, s->size);
stream_free(s); stream_free(s);
return true; return true;
} }
boolean rpch_in_send_keep_alive(rdpRpch* rpch) boolean rpc_in_send_keep_alive(rdpRpch* rpch)
{ {
STREAM* s = stream_new(28); STREAM* s = stream_new(28);
@ -718,14 +583,14 @@ boolean rpch_in_send_keep_alive(rdpRpch* rpch)
stream_write_uint32(s, ckCommandType); stream_write_uint32(s, ckCommandType);
stream_write_uint32(s, ClientKeepalive); stream_write_uint32(s, ClientKeepalive);
rpch_in_write(rpch, s->data, stream_get_length(s)); rpc_in_write(rpch, s->data, stream_get_length(s));
stream_free(s); stream_free(s);
return true; return true;
} }
boolean rpch_in_send_bind(rdpRpch* rpch) boolean rpc_in_send_bind(rdpRpch* rpch)
{ {
rpcconn_bind_hdr_t* bind_pdu; rpcconn_bind_hdr_t* bind_pdu;
rdpSettings* settings = rpch->settings; rdpSettings* settings = rpch->settings;
@ -844,7 +709,7 @@ boolean rpch_in_send_bind(rdpRpch* rpch)
stream_write(pdu, &bind_pdu->auth_verifier.auth_type, 8); /* assumed that uint8 pointer is 32bit long (4 bytes) */ stream_write(pdu, &bind_pdu->auth_verifier.auth_type, 8); /* assumed that uint8 pointer is 32bit long (4 bytes) */
stream_write(pdu, bind_pdu->auth_verifier.auth_value, bind_pdu->auth_length); stream_write(pdu, bind_pdu->auth_verifier.auth_value, bind_pdu->auth_length);
rpch_in_write(rpch, pdu->data, stream_get_length(pdu)); rpc_in_write(rpch, pdu->data, stream_get_length(pdu));
/* TODO there is some allocated memory */ /* TODO there is some allocated memory */
xfree(bind_pdu); xfree(bind_pdu);
@ -852,7 +717,7 @@ boolean rpch_in_send_bind(rdpRpch* rpch)
return true; return true;
} }
boolean rpch_in_send_rpc_auth_3(rdpRpch* rpch) boolean rpc_in_send_rpc_auth_3(rdpRpch* rpch)
{ {
rpcconn_rpc_auth_3_hdr_t* rpc_auth_3_pdu; rpcconn_rpc_auth_3_hdr_t* rpc_auth_3_pdu;
STREAM* ntlm_stream = stream_new(0xFFFF); STREAM* ntlm_stream = stream_new(0xFFFF);
@ -896,14 +761,14 @@ boolean rpch_in_send_rpc_auth_3(rdpRpch* rpch)
stream_write(pdu, &rpc_auth_3_pdu->auth_verifier.auth_type, 8); stream_write(pdu, &rpc_auth_3_pdu->auth_verifier.auth_type, 8);
stream_write(pdu, rpc_auth_3_pdu->auth_verifier.auth_value, rpc_auth_3_pdu->auth_length); stream_write(pdu, rpc_auth_3_pdu->auth_verifier.auth_value, rpc_auth_3_pdu->auth_length);
rpch_in_write(rpch, pdu->data, stream_get_length(pdu)); rpc_in_write(rpch, pdu->data, stream_get_length(pdu));
xfree(rpc_auth_3_pdu); xfree(rpc_auth_3_pdu);
return true; return true;
} }
boolean rpch_in_send_flow_control(rdpRpch* rpch) boolean rpc_in_send_flow_control(rdpRpch* rpch)
{ {
STREAM* s = stream_new(56); STREAM* s = stream_new(56);
@ -944,14 +809,14 @@ boolean rpch_in_send_flow_control(rdpRpch* rpch)
stream_write_uint32(s, aaa); stream_write_uint32(s, aaa);
stream_write(s, b, 16); stream_write(s, b, 16);
rpch_in_write(rpch, s->data, stream_get_length(s)); rpc_in_write(rpch, s->data, stream_get_length(s));
stream_free(s); stream_free(s);
return true; return true;
} }
boolean rpch_in_send_ping(rdpRpch* rpch) boolean rpc_in_send_ping(rdpRpch* rpch)
{ {
STREAM* s = stream_new(20); STREAM* s = stream_new(20);
@ -977,14 +842,14 @@ boolean rpch_in_send_ping(rdpRpch* rpch)
stream_write_uint16(s, flags); stream_write_uint16(s, flags);
stream_write_uint16(s, num_commands); stream_write_uint16(s, num_commands);
rpch_in_write(rpch, s->data, stream_get_length(s)); rpc_in_write(rpch, s->data, stream_get_length(s));
stream_free(s); stream_free(s);
return true; return true;
} }
int rpch_out_read_http_header(rdpRpch* rpch) int rpc_out_read_http_header(rdpRpch* rpch)
{ {
int status; int status;
STREAM* http_stream; STREAM* http_stream;
@ -1040,7 +905,7 @@ int rpch_out_read_http_header(rdpRpch* rpch)
return status; return status;
} }
int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length) int rpc_rts_recv(rdpRpch* rpch, uint8* pdu, int length)
{ {
int i; int i;
uint32 CommandType; uint32 CommandType;
@ -1050,7 +915,7 @@ int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length)
if (flags & RTS_FLAG_PING) if (flags & RTS_FLAG_PING)
{ {
rpch_in_send_keep_alive(rpch); rpc_in_send_keep_alive(rpch);
return 0; return 0;
} }
@ -1128,7 +993,7 @@ int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length)
return 0; return 0;
} }
int rpch_out_read(rdpRpch* rpch, uint8* data, int length) int rpc_out_read(rdpRpch* rpch, uint8* data, int length)
{ {
int status; int status;
uint8* pdu; uint8* pdu;
@ -1138,11 +1003,11 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length)
rdpRpchHTTP* http_out = rpch->http_out; rdpRpchHTTP* http_out = rpch->http_out;
if (rpch->AwailableWindow < 0x00008FFF) /* Just a simple workaround */ if (rpch->AwailableWindow < 0x00008FFF) /* Just a simple workaround */
rpch_in_send_flow_control(rpch); /* Send FlowControlAck every time AW reaches the half */ rpc_in_send_flow_control(rpch); /* Send FlowControlAck every time AW reaches the half */
if (http_out->remContentLength <= 0xFFFF) /* TODO make ChannelRecycling */ if (http_out->remContentLength <= 0xFFFF) /* TODO make ChannelRecycling */
{ {
if (rpch_out_read_http_header(rpch) < 0) if (rpc_out_read_http_header(rpch) < 0)
return -1; return -1;
} }
@ -1169,7 +1034,7 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length)
if (ptype == 0x14) /* RTS PDU */ if (ptype == 0x14) /* RTS PDU */
{ {
rpch_proceed_RTS(rpch, pdu, frag_length); rpc_rts_recv(rpch, pdu, frag_length);
xfree(pdu); xfree(pdu);
return 0; return 0;
} }
@ -1201,14 +1066,14 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length)
return frag_length; return frag_length;
} }
int rpch_out_recv_bind_ack(rdpRpch* rpch) int rpc_out_recv_bind_ack(rdpRpch* rpch)
{ {
uint16 frag_length; uint16 frag_length;
uint16 auth_length; uint16 auth_length;
STREAM* ntlmssp_stream; STREAM* ntlmssp_stream;
int pdu_length = 0x8FFF; /* 32KB buffer */ int pdu_length = 0x8FFF; /* 32KB buffer */
uint8* pdu = xmalloc(pdu_length); uint8* pdu = xmalloc(pdu_length);
int status = rpch_out_read(rpch, pdu, pdu_length); int status = rpc_out_read(rpch, pdu, pdu_length);
DEBUG_RPCH("TODO: complete NTLM integration"); DEBUG_RPCH("TODO: complete NTLM integration");
@ -1230,7 +1095,7 @@ int rpch_out_recv_bind_ack(rdpRpch* rpch)
return status; return status;
} }
int rpch_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum) int rpc_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum)
{ {
int i; int i;
int status = -1; int status = -1;
@ -1297,7 +1162,7 @@ int rpch_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum)
stream_write(pdu, request_pdu->auth_verifier.auth_value, request_pdu->auth_length); stream_write(pdu, request_pdu->auth_verifier.auth_value, request_pdu->auth_length);
status = rpch_in_write(rpch, pdu->data, pdu->p - pdu->data); status = rpc_in_write(rpch, pdu->data, pdu->p - pdu->data);
xfree(request_pdu->auth_verifier.auth_value); xfree(request_pdu->auth_verifier.auth_value);
xfree(request_pdu->auth_verifier.auth_pad); xfree(request_pdu->auth_verifier.auth_pad);
@ -1341,7 +1206,7 @@ int rpch_read(rdpRpch* rpch, uint8* data, int length)
while (true) while (true)
{ {
status = rpch_out_read(rpch, rpch_data, rpch_length); status = rpc_out_read(rpch, rpch_data, rpch_length);
if (status == 0) if (status == 0)
{ {
@ -1400,7 +1265,7 @@ boolean rpch_connect(rdpRpch* rpch)
uint8* pdu; uint8* pdu;
int pdu_length; int pdu_length;
if (!rpch_out_send_CONN_A1(rpch)) if (!rpc_out_send_CONN_A1(rpch))
{ {
printf("rpch_out_send_CONN_A1 fault!\n"); printf("rpch_out_send_CONN_A1 fault!\n");
return false; return false;
@ -1409,32 +1274,32 @@ boolean rpch_connect(rdpRpch* rpch)
pdu_length = 0xFFFF; pdu_length = 0xFFFF;
pdu = xmalloc(pdu_length); pdu = xmalloc(pdu_length);
status = rpch_out_read(rpch, pdu, pdu_length); status = rpc_out_read(rpch, pdu, pdu_length);
if (!rpch_in_send_CONN_B1(rpch)) if (!rpc_in_send_CONN_B1(rpch))
{ {
printf("rpch_out_send_CONN_A1 fault!\n"); printf("rpch_out_send_CONN_A1 fault!\n");
return false; return false;
} }
status = rpch_out_read(rpch, pdu, pdu_length); status = rpc_out_read(rpch, pdu, pdu_length);
/* [MS-RPCH] 3.2.1.5.3.1 Connection Establishment /* [MS-RPCH] 3.2.1.5.3.1 Connection Establishment
* at this point VirtualChannel is created * at this point VirtualChannel is created
*/ */
if (!rpch_in_send_bind(rpch)) if (!rpc_in_send_bind(rpch))
{ {
printf("rpch_out_send_bind fault!\n"); printf("rpch_out_send_bind fault!\n");
return false; return false;
} }
if (!rpch_out_recv_bind_ack(rpch)) if (!rpc_out_recv_bind_ack(rpch))
{ {
printf("rpch_out_recv_bind_ack fault!\n"); printf("rpch_out_recv_bind_ack fault!\n");
return false; return false;
} }
if (!rpch_in_send_rpc_auth_3(rpch)) if (!rpc_in_send_rpc_auth_3(rpch))
{ {
printf("rpch_out_send_rpc_auth_3 fault!\n"); printf("rpch_out_send_rpc_auth_3 fault!\n");
return false; return false;

View File

@ -25,6 +25,7 @@ typedef struct rdp_rpch rdpRpch;
typedef struct rdp_rpch_http rdpRpchHTTP; typedef struct rdp_rpch_http rdpRpchHTTP;
#include "tcp.h" #include "tcp.h"
#include "http.h"
#include <time.h> #include <time.h>
#include <freerdp/types.h> #include <freerdp/types.h>
@ -640,7 +641,7 @@ void ntlm_free(rdpNtlm* ntlm);
boolean rpch_attach(rdpRpch* rpch, rdpTcp* tcp_in, rdpTcp* tcp_out, rdpTls* tls_in, rdpTls* tls_out); boolean rpch_attach(rdpRpch* rpch, rdpTcp* tcp_in, rdpTcp* tcp_out, rdpTls* tls_in, rdpTls* tls_out);
boolean rpch_connect(rdpRpch* rpch); boolean rpch_connect(rdpRpch* rpch);
int rpch_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum); int rpc_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum);
int rpch_read(rdpRpch* rpch, uint8* data, int length); int rpch_read(rdpRpch* rpch, uint8* data, int length);
rdpRpch* rpch_new(rdpSettings* settings); rdpRpch* rpch_new(rdpSettings* settings);

View File

@ -229,7 +229,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/ */
DEBUG_TSG("TsProxyCreateTunnel"); DEBUG_TSG("TsProxyCreateTunnel");
status = rpch_write(rpch, tsg_packet1, sizeof(tsg_packet1), 1); status = rpc_write(rpch, tsg_packet1, sizeof(tsg_packet1), 1);
if (status <= 0) if (status <= 0)
{ {
@ -270,7 +270,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/ */
DEBUG_TSG("TsProxyAuthorizeTunnel"); DEBUG_TSG("TsProxyAuthorizeTunnel");
status = rpch_write(rpch, tsg_packet2, sizeof(tsg_packet2), 2); status = rpc_write(rpch, tsg_packet2, sizeof(tsg_packet2), 2);
if (status <= 0) if (status <= 0)
{ {
@ -300,7 +300,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/ */
DEBUG_TSG("TsProxyMakeTunnelCall"); DEBUG_TSG("TsProxyMakeTunnelCall");
status = rpch_write(rpch, tsg_packet3, sizeof(tsg_packet3), 3); status = rpc_write(rpch, tsg_packet3, sizeof(tsg_packet3), 3);
if (status <= 0) if (status <= 0)
{ {
@ -337,7 +337,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/ */
DEBUG_TSG("TsProxyCreateChannel"); DEBUG_TSG("TsProxyCreateChannel");
status = rpch_write(rpch, s_p4->data, s_p4->size, 4); status = rpc_write(rpch, s_p4->data, s_p4->size, 4);
if (status <= 0) if (status <= 0)
{ {
@ -374,7 +374,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
*/ */
DEBUG_TSG("TsProxySetupReceivePipe"); DEBUG_TSG("TsProxySetupReceivePipe");
status = rpch_write(rpch, tsg_packet5, sizeof(tsg_packet5), 8); status = rpc_write(rpch, tsg_packet5, sizeof(tsg_packet5), 8);
if (status <= 0) if (status <= 0)
{ {
@ -411,7 +411,7 @@ int tsg_write(rdpTsg* tsg, uint8* data, uint32 length)
memcpy(tsg_pkg + 32 + length, pp, 8); memcpy(tsg_pkg + 32 + length, pp, 8);
status = rpch_write(tsg->rpch, tsg_pkg, tsg_length, opnum); status = rpc_write(tsg->rpch, tsg_pkg, tsg_length, opnum);
xfree(tsg_pkg); xfree(tsg_pkg);
stream_free(s); stream_free(s);

View File

@ -531,6 +531,30 @@ void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_le
BIO_free_all(b64); BIO_free_all(b64);
} }
char* crypto_encode_base64(uint8* data, int length)
{
BIO* bmem;
BIO* b64;
BUF_MEM *bptr;
char* base64_string;
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, data, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
base64_string = xmalloc(bptr->length);
memcpy(base64_string, bptr->data, bptr->length - 1);
base64_string[bptr->length] = '\0';
BIO_free_all(b64);
return base64_string;
}
void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length) void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length)
{ {
BIO *b64, *bmem; BIO *b64, *bmem;