From fa7900d293dbe6814484d109f9510a4bedb37245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 16 Apr 2012 16:21:46 -0400 Subject: [PATCH] libfreerdp-core: start using HTTP utils for NTLM HTTP authentication --- include/freerdp/crypto/crypto.h | 1 + libfreerdp-core/http.c | 278 +++++++++++++++++++++++++++++-- libfreerdp-core/http.h | 31 +++- libfreerdp-core/rpc.c | 287 +++++++++----------------------- libfreerdp-core/rpc.h | 3 +- libfreerdp-core/tsg.c | 12 +- libfreerdp-crypto/crypto.c | 24 +++ 7 files changed, 402 insertions(+), 234 deletions(-) diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index de135abda..5cbd074be 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -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_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_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length); diff --git a/libfreerdp-core/http.c b/libfreerdp-core/http.c index 241f6e49b..e055404d9 100644 --- a/libfreerdp-core/http.c +++ b/libfreerdp-core/http.c @@ -97,9 +97,19 @@ void http_request_set_uri(HttpRequest* http_request, char* 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, ...) \ - _str = xmalloc(snprintf(NULL, 0, _fmt, ## __VA_ARGS__)); \ - snprintf(_str, snprintf(NULL, 0, _fmt, ## __VA_ARGS__), _fmt, ## __VA_ARGS__); + _str = xmalloc(snprintf(NULL, 0, _fmt, ## __VA_ARGS__) + 1); \ + snprintf(_str, snprintf(NULL, 0, _fmt, ## __VA_ARGS__) + 1, _fmt, ## __VA_ARGS__); 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; int length = 0; - http_request->count = 10; + http_request->count = 9; 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[1], "Accept: %s\n", http_context->Accept); - http_encode_line(http_request->lines[2], "Cache-Control: %s\n", http_context->CacheControl); - http_encode_line(http_request->lines[3], "Connection: %s\n", http_context->Connection); - http_encode_line(http_request->lines[4], "Content-Length: %d\n", http_request->ContentLength); - http_encode_line(http_request->lines[5], "User-Agent: %s\n", http_context->UserAgent); - http_encode_line(http_request->lines[6], "Host: %s\n", http_context->Host); - http_encode_line(http_request->lines[7], "Pragma: %s\n", 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"); + 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", http_context->Accept); + http_encode_line(http_request->lines[2], "Cache-Control: %s", http_context->CacheControl); + http_encode_line(http_request->lines[3], "Connection: %s", http_context->Connection); + http_encode_line(http_request->lines[4], "Content-Length: %d", http_request->ContentLength); + http_encode_line(http_request->lines[5], "User-Agent: %s", http_context->UserAgent); + http_encode_line(http_request->lines[6], "Host: %s", http_context->Host); + http_encode_line(http_request->lines[7], "Pragma: %s", http_context->Pragma); + + 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++) { - 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); for (i = 0; i < http_request->count; i++) { stream_write(s, http_request->lines[i], strlen(http_request->lines[i])); + stream_write(s, "\n", 1); xfree(http_request->lines[i]); } + stream_write(s, "\n", 1); 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); return s; @@ -161,3 +186,228 @@ void http_request_free(HttpRequest* 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); + } +} diff --git a/libfreerdp-core/http.h b/libfreerdp-core/http.h index 6c9b007fe..06f50e97d 100644 --- a/libfreerdp-core/http.h +++ b/libfreerdp-core/http.h @@ -20,7 +20,12 @@ #ifndef 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 +#include #include struct _http_context @@ -34,7 +39,6 @@ struct _http_context char* Connection; char* Pragma; }; -typedef struct _http_context HttpContext; void http_context_set_method(HttpContext* http_context, char* method); void http_context_set_uri(HttpContext* http_context, char* uri); @@ -55,18 +59,41 @@ struct _http_request char* Method; char* URI; + char* AuthScheme; + char* AuthParam; char* Authorization; int ContentLength; char* Content; }; -typedef struct _http_request HttpRequest; void http_request_set_method(HttpRequest* http_request, char* method); 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); HttpRequest* http_request_new(); 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 */ diff --git a/libfreerdp-core/rpc.c b/libfreerdp-core/rpc.c index ed0c77c7c..1f391df8b 100644 --- a/libfreerdp-core/rpc.c +++ b/libfreerdp-core/rpc.c @@ -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; - char* int_str; - int total_length; - int int_str_length; - int command_length; - rdpSettings* settings; - int tsg_hostname_length; - int ntlm_token_base64_length; - uint8* ntlm_token_base64_data; + char* base64_ntlm_token; + HttpContext* http_context; + HttpRequest* http_request; - 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); - tsg_hostname_length = strlen(settings->tsg_hostname); + if (strcmp(command, "RPC_IN_DATA") == 0) + http_context = rpch->http_in->context; + else + http_context = rpch->http_out->context; - int_str = xmalloc(int_str_length + 1); - snprintf(int_str, int_str_length + 1, "%d", length); + http_request = http_request_new(); - 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 + - tsg_hostname_length + 1 + 110 + 20 + ntlm_token_base64_length + 2; + http_request_set_method(http_request, http_context->Method); + 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); - 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); + s = http_request_write(http_context, http_request); return s; } -boolean rpch_out_connect_http(rdpRpch* rpch) +boolean rpc_out_connect_http(rdpRpch* rpch) { STREAM* http_stream; STREAM* ntlm_stream; + HttpResponse* http_response; int decoded_ntlm_http_length; int encoded_ntlm_http_length; uint8* decoded_ntlm_http_data = NULL; @@ -236,13 +216,13 @@ boolean rpch_out_connect_http(rdpRpch* rpch) 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_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); tls_write(tls_out, http_stream->data, http_stream->size); @@ -256,73 +236,15 @@ boolean rpch_out_connect_http(rdpRpch* rpch) uint8 buffer_byte; http_out->contentLength = 0; - /* Example for how not to do clear code, sorry for that */ - 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 */ + http_response = http_response_recv(tls_out); DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data); stream_clear(http_stream); 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 */ return false; @@ -336,7 +258,7 @@ boolean rpch_out_connect_http(rdpRpch* rpch) http_out->contentLength = 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); tls_write(tls_out, http_stream->data, http_stream->size); @@ -351,10 +273,11 @@ boolean rpch_out_connect_http(rdpRpch* rpch) return true; } -boolean rpch_in_connect_http(rdpRpch* rpch) +boolean rpc_in_connect_http(rdpRpch* rpch) { STREAM* ntlm_stream; STREAM* http_stream; + HttpResponse* http_response; int decoded_ntlm_http_length; int encoded_ntlm_http_length; uint8* decoded_ntlm_http_data = NULL; @@ -372,7 +295,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch) 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); tls_write(tls_in, http_stream->data, http_stream->size); @@ -388,73 +311,15 @@ boolean rpch_in_connect_http(rdpRpch* rpch) uint8 buffer_byte; http_in->contentLength = 0; - /* Example for how not to do clear code, sorry for that */ - 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 */ + http_response = http_response_recv(tls_in); DEBUG_RPCH("\nRecv:\n%s\n", http_stream->data); stream_clear(http_stream); 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 */ return false; @@ -468,7 +333,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch) http_in->contentLength = 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); @@ -486,7 +351,7 @@ boolean rpch_in_connect_http(rdpRpch* rpch) 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 status = -1; @@ -495,7 +360,7 @@ int rpch_out_write(rdpRpch* rpch, uint8* data, int length) if (http_out->state == RPCH_HTTP_DISCONNECTED) { - if (!rpch_out_connect_http(rpch)) + if (!rpc_out_connect_http(rpch)) return false; } @@ -526,7 +391,7 @@ int rpch_out_write(rdpRpch* rpch, uint8* data, int length) 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 status = -1; @@ -535,7 +400,7 @@ int rpch_in_write(rdpRpch* rpch, uint8* data, int length) if (http_in->state == RPCH_HTTP_DISCONNECTED) { - if (!rpch_in_connect_http(rpch)) + if (!rpc_in_connect_http(rpch)) return -1; } @@ -567,14 +432,14 @@ int rpch_in_write(rdpRpch* rpch, uint8* data, int length) return sent; } -uint8* rpch_create_cookie() +uint8* rpc_create_cookie() { uint8* ret = xmalloc(16); RAND_pseudo_bytes(ret, 16); return ret; } -boolean rpch_out_send_CONN_A1(rdpRpch* rpch) +boolean rpc_out_send_CONN_A1(rdpRpch* rpch) { STREAM* pdu = stream_new(76); @@ -597,8 +462,8 @@ boolean rpch_out_send_CONN_A1(rdpRpch* rpch) uint32 rwsCommandType = 0x00000000; uint32 receiveWindowSize = 0x00010000; - rpch->virtualConnectionCookie = rpch_create_cookie(); /* 16 bytes */ - rpch->OUTChannelCookie = rpch_create_cookie(); /* 16 bytes */ + rpch->virtualConnectionCookie = rpc_create_cookie(); /* 16 bytes */ + rpch->OUTChannelCookie = rpc_create_cookie(); /* 16 bytes */ rpch->AwailableWindow = receiveWindowSize; 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, receiveWindowSize); - rpch_out_write(rpch, pdu->data, stream_get_length(pdu)); + rpc_out_write(rpch, pdu->data, stream_get_length(pdu)); stream_free(pdu); return true; } -boolean rpch_in_send_CONN_B1(rdpRpch* rpch) +boolean rpc_in_send_CONN_B1(rdpRpch* rpch) { STREAM* s = stream_new(104); @@ -654,8 +519,8 @@ boolean rpch_in_send_CONN_B1(rdpRpch* rpch) uint32 agidCommandType = 0x0000000c; uint8* AssociationGroupId; - rpch->INChannelCookie = rpch_create_cookie(); /* 16 bytes */ - AssociationGroupId = rpch_create_cookie(); /* 16 bytes */ + rpch->INChannelCookie = rpc_create_cookie(); /* 16 bytes */ + AssociationGroupId = rpc_create_cookie(); /* 16 bytes */ stream_write_uint8(s, rpc_vers); 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_seal(s); - rpch_in_write(rpch, s->data, s->size); + rpc_in_write(rpch, s->data, s->size); stream_free(s); return true; } -boolean rpch_in_send_keep_alive(rdpRpch* rpch) +boolean rpc_in_send_keep_alive(rdpRpch* rpch) { 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, ClientKeepalive); - rpch_in_write(rpch, s->data, stream_get_length(s)); + rpc_in_write(rpch, s->data, stream_get_length(s)); stream_free(s); return true; } -boolean rpch_in_send_bind(rdpRpch* rpch) +boolean rpc_in_send_bind(rdpRpch* rpch) { rpcconn_bind_hdr_t* bind_pdu; 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_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 */ xfree(bind_pdu); @@ -852,7 +717,7 @@ boolean rpch_in_send_bind(rdpRpch* rpch) 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; 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_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); return true; } -boolean rpch_in_send_flow_control(rdpRpch* rpch) +boolean rpc_in_send_flow_control(rdpRpch* rpch) { STREAM* s = stream_new(56); @@ -944,14 +809,14 @@ boolean rpch_in_send_flow_control(rdpRpch* rpch) stream_write_uint32(s, aaa); 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); return true; } -boolean rpch_in_send_ping(rdpRpch* rpch) +boolean rpc_in_send_ping(rdpRpch* rpch) { 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, 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); return true; } -int rpch_out_read_http_header(rdpRpch* rpch) +int rpc_out_read_http_header(rdpRpch* rpch) { int status; STREAM* http_stream; @@ -1040,7 +905,7 @@ int rpch_out_read_http_header(rdpRpch* rpch) return status; } -int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length) +int rpc_rts_recv(rdpRpch* rpch, uint8* pdu, int length) { int i; uint32 CommandType; @@ -1050,7 +915,7 @@ int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length) if (flags & RTS_FLAG_PING) { - rpch_in_send_keep_alive(rpch); + rpc_in_send_keep_alive(rpch); return 0; } @@ -1128,7 +993,7 @@ int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length) return 0; } -int rpch_out_read(rdpRpch* rpch, uint8* data, int length) +int rpc_out_read(rdpRpch* rpch, uint8* data, int length) { int status; uint8* pdu; @@ -1138,11 +1003,11 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length) rdpRpchHTTP* http_out = rpch->http_out; 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 (rpch_out_read_http_header(rpch) < 0) + if (rpc_out_read_http_header(rpch) < 0) return -1; } @@ -1169,7 +1034,7 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length) if (ptype == 0x14) /* RTS PDU */ { - rpch_proceed_RTS(rpch, pdu, frag_length); + rpc_rts_recv(rpch, pdu, frag_length); xfree(pdu); return 0; } @@ -1201,14 +1066,14 @@ int rpch_out_read(rdpRpch* rpch, uint8* data, int length) return frag_length; } -int rpch_out_recv_bind_ack(rdpRpch* rpch) +int rpc_out_recv_bind_ack(rdpRpch* rpch) { uint16 frag_length; uint16 auth_length; STREAM* ntlmssp_stream; int pdu_length = 0x8FFF; /* 32KB buffer */ 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"); @@ -1230,7 +1095,7 @@ int rpch_out_recv_bind_ack(rdpRpch* rpch) 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 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); - 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_pad); @@ -1341,7 +1206,7 @@ int rpch_read(rdpRpch* rpch, uint8* data, int length) while (true) { - status = rpch_out_read(rpch, rpch_data, rpch_length); + status = rpc_out_read(rpch, rpch_data, rpch_length); if (status == 0) { @@ -1400,7 +1265,7 @@ boolean rpch_connect(rdpRpch* rpch) uint8* pdu; 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"); return false; @@ -1409,32 +1274,32 @@ boolean rpch_connect(rdpRpch* rpch) pdu_length = 0xFFFF; 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"); 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 * 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"); return false; } - if (!rpch_out_recv_bind_ack(rpch)) + if (!rpc_out_recv_bind_ack(rpch)) { printf("rpch_out_recv_bind_ack fault!\n"); 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"); return false; diff --git a/libfreerdp-core/rpc.h b/libfreerdp-core/rpc.h index 16c1a0852..8a16aa37b 100644 --- a/libfreerdp-core/rpc.h +++ b/libfreerdp-core/rpc.h @@ -25,6 +25,7 @@ typedef struct rdp_rpch rdpRpch; typedef struct rdp_rpch_http rdpRpchHTTP; #include "tcp.h" +#include "http.h" #include #include @@ -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_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); rdpRpch* rpch_new(rdpSettings* settings); diff --git a/libfreerdp-core/tsg.c b/libfreerdp-core/tsg.c index 760be0017..4e83544f2 100644 --- a/libfreerdp-core/tsg.c +++ b/libfreerdp-core/tsg.c @@ -229,7 +229,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port) */ 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) { @@ -270,7 +270,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port) */ 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) { @@ -300,7 +300,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port) */ 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) { @@ -337,7 +337,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port) */ 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) { @@ -374,7 +374,7 @@ boolean tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port) */ 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) { @@ -411,7 +411,7 @@ int tsg_write(rdpTsg* tsg, uint8* data, uint32 length) 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); stream_free(s); diff --git a/libfreerdp-crypto/crypto.c b/libfreerdp-crypto/crypto.c index d84e0e68c..12a1d6c53 100644 --- a/libfreerdp-crypto/crypto.c +++ b/libfreerdp-crypto/crypto.c @@ -531,6 +531,30 @@ void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_le 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) { BIO *b64, *bmem;